不带头节点的单链表

.h

# pragma once
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include<assert.h>

typedef int DataType;

typedef struct Node
{
	struct Node* _pNext;
	DataType _data;
}Node, *PNode;


//////////////////不带头结点的单链表////////////////////////////////////// 
// .h 
// 链表初始化 
void SListInit(PNode* pHead);//需要改变外部实参的指向,所以传指针;否则,相当于值传递

// 尾插 
void SListPushBack(PNode* pHead, DataType data);

// 尾删 
void SListPopBack(PNode* pHead);

// 头插 
void SListPushFront(PNode* pHead, DataType data);

// 头删 
void SListPopFront(PNode* pHead);

//// 查找值为data的结点,返回该结点在链表中的位置 
PNode SListFind(PNode pHead, DataType data);
//
// 任意位置的插入,在链表pos位置后插入结点data 
void SListInsert(PNode* pHead, PNode pos, DataType data);

//任意位置的删除, 删除链表pos位置上的结点 
void SListErase(PNode* pHead, PNode pos);
//
//// 销毁单链表 
void SListDestroy(PNode* pHead);
//
//// 求链表中结点的个数 
int SListSize(PNode pHead);
//
//// 将链表中的结点清空 
void SListClear(PNode* pHead);
//
// 获取结点 
PNode BuySListNode(DataType data);
//
//// 获取链表中的最后一个结点,返回该结点的地址 
//PNode SListBack(PNode pHead);

//打印单链表
void PrintList(PNode *pHead);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
//从尾到头打印单链表
void PrintListFromTail2Head(PNode pHead);
// 删除链表的非尾结点,要求不能遍历链表 (删除后一个节点,替换到要删除的位置)
void DeleteNotTailNode(PNode pos);

// 在链表pos位置前插入值为data的结点 (插入新节点,后交换前一个节点与新节点)
void InsertPosFront(PNode pos, DataType data);

// 用单链表模拟实现约瑟夫环 
// 约瑟夫环 (1.报数 2、删除节点)
void JosephCircle(PNode* pHead, const int M);
//找尾节点(找链表中最后一个节点的位置)
PNode slistBack(PNode pHead);

// 使用冒泡方式对单链表进行排序 
void BubbleSort(PNode pHead);

// 单链表的逆序---三个指针 
 //直接在该链表中插入需要O(n^2);借助一个链表需要O(n),所以用三个指针
void ReverseSList(PNode* pHead);

// 单链表的逆序---使用头插法 
PNode ReverseSListOP(PNode pHead);

// 合并两个有序链表,合并起来依然要有序 
PNode MergeSList(PNode pHead1, PNode pHead2);

// 查找链表的中间结点,要求只能遍历一次链表 
PNode FindMiddleNode(PNode pHead);

// 查找链表的倒数第K个结点 (一个指针先走k步后,两个指针一起走:
//1、k>链表中的节点个数:NULL
//2、k<=链表中的节点个数:pSLow,pFast
PNode FindLastKNode(PNode pHead, int K);


 // 删除链表的倒数第K个结点,要求只能遍历链表一次 
PNode DeleteLastKNode(PNode pHead, int K);


// 判断两个单链表是否相交---链表不带环 
//1、第一个链表的最后一个节点指向第二个链表的最后一个节点
//2、第一个链表的最后一个节点指向第二个链表的任意一个节点
//3、第一个链表的最后一个节点指向第二个链表的第一个节点
int IsCrossWithoutCircle(PNode pHead1, PNode pHead2);

// 如果相交 获取交点 
// 求不带环单链表相交交点 
PNode GetCrossNode(PNode pHead1, PNode pHead2);

// 判断链表是否带环 
PNode IsCircle(PNode pHead);

// 求环的长度 
int GetCircleLen(PNode pHead);

// 求环的入口点--注意推断过程 
PNode GetEnterNode(PNode pHead, PNode pMeetNode);

// 判断链表是否带环,链表可能带环 
int IsListCrossWithCircle(PNode pHead1, PNode pHead2);

// 复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求
//复制这个链表,返回复制后的新链表
//1、在原链表每个节点后插入值相同的新节点
//2、给新节点插入节点的随机指针域赋值
//3、将插入的新节点从链表中拆下来
typedef struct CpmplexListNode{
	struct CpmplexListNode *pNext;
	struct CpmplexListNode *pRandom;//可以指向链表中的任意节点,也包括自己和空
	DataType data;
}ComplexListNode,*pComplexListNode;
pComplexListNode CopyComplexList(pComplexListNode pHead);
.c
 
  
 
 
# define _CRE_SECURE_NO_WARNINGS 1
# include"Link.h"
void SListInit(PNode* pHead)
{
	assert(pHead);
	*pHead = NULL;
}
PNode BuySListNode(DataType data)
{
	PNode pNewNode = (PNode)malloc(sizeof(Node));
	if (pNewNode == NULL)
		return NULL;
	pNewNode->_pNext = NULL;
	pNewNode->_data = data;
	return pNewNode;
}
//尾插:
//1、空链表(链表已经存在,但是里面没有节点,直接插入)
//2、非空
//(1)一个节点
//(2)多个节点(一个节点记录当前位置pPre,一个节点向后走pCur
void SListPushBack(PNode* pHead, DataType data)//需要改变外部实参的指向,所以传指针;否则,相当于值传递
{
	PNode pNewNode = NULL;
	assert(pHead);//phead为空这种情况一定不存在,检测链表是否存在,若是pHead不合理(非法)会触发assert,导致程序崩溃
	//if(NULL==pHead) return;pHead为空这种情况有可能存在,检测链表是否存在
	pNewNode = BuySListNode(data);
	if (NULL == *pHead)
	{
		*pHead = pNewNode;
 	}
	else
	{
		PNode pCur = *pHead;
		while (pCur->_pNext)
		{
			//pCur++必须应用于空间连续的情况
			pCur = pCur->_pNext;
		}
		pCur->_pNext = pNewNode;
	}
}
//尾删
//1、空链表,直接返回
//2、只有一个节点,直接删除,pHead置空
//3、多个节点,先找倒数第二个节点,倒数第二个节点的下一个节点为当前需要被删除的位置,置为空。
 void SListPopBack(PNode* pHead, DataType data)
{
	PNode pDelNode = *pHead;
	assert(pHead);
	if (NULL == *pHead)
		return;
	else if (NULL == (*pHead)->_pNext)//找到倒数第二个节点,再将倒数第一个节点置为空
	{ 
		//只有一个节点
		free(*pHead);
		*pHead = NULL;
	}
	else
	{
		PNode pCur = *pHead;
		while (pCur->_pNext->_pNext)
		{
			pCur = pCur->_pNext;
		}
		free(pCur->_pNext);
		pCur->_pNext = NULL;
	}
}
//头插
//1、空链表
//2、非空:(1)新节点链接链表(新节点的下一个位置指向头指针)
          //(2)头指针指向新节点
void SListPushFront(PNode* pHead, DataType data)
{
	PNode pNewNode = NULL;
	assert(pHead);
	pNewNode = BuySListNode(data);
	if (NULL == pNewNode)
		return;
	pNewNode->_pNext = *pHead;
	*pHead = pNewNode;
}
//头删
//1、空链表,直接返回
//2、只有一个节点,直接删除
//3、多个节点(1)保存第一个节点
            //(2)改变指向
           //  (3)删除节点
void SListPopFront(PNode* pHead)
{
	PNode pDelNode = NULL; //保存第一个节点
	assert(pHead);
	if (NULL == *pHead)
		return;
	pDelNode = *pHead;
	*pHead = pDelNode->_pNext;//改变指向
	free(pDelNode);//删除节点
}
//找当前节点
PNode SListFind(PNode pHead, DataType data)
{
	PNode pCur = pHead;
 	while (pCur)
	{
		if (pCur->_data == data)
		{
			return pCur;
		}
		pCur = pCur->_pNext;
	}
	return NULL;
}
// 任意位置的插入,在链表pos位置后插入结点data 
//1、查找pos节点的位置
//2、插入pos节点之后的位置
void SListInsert(PNode* pHead, PNode pos, DataType data)
{
	PNode pNewNode = NULL;
	assert(pHead);
	if (NULL == *pHead || NULL == pos)//空链表或者不给定位置,则不能插入
		return;
 	pNewNode = BuySListNode(data);
	if (NULL == pNewNode)
		return;
	pNewNode->_pNext = pos->_pNext;
	pos->_pNext = pNewNode;
}


 
//任意位置的删除, 删除链表pos位置上的结点
//找pos的位置
//(1)pos在链表头部,头删
//(2)pos在其他位置,找到pos的前一个位置;
void SListErase(PNode* pHead, PNode pos)
{
	assert(pHead);
	if ((NULL == *pHead) || (NULL == pos))
		return;
	if (pos == *pHead)//pos在链表头部,头删
		SListPopFront(pHead);
	else
	{
		PNode pCur = *pHead;//pos在其他位置:找到pos的前一个位置;
		while ((pCur) && (pCur->_pNext != pos))
		{
			pCur = pCur->_pNext;
			if (pCur)
			{
				pCur->_pNext = pos->_pNext;
				free(pos);
			}
		}
	}
}
//将链表中的结点清空
//有节点先标记节点
//按头删的方法删除
void SListClear(PNode* pHead)
{
	PNode pDelnode = NULL;
	assert(pHead);
	while (*pHead)
	{
		PNode pDelnode = *pHead;
		*pHead = pDelnode->_pNext;
		free(pDelnode);

	}
}
//销毁单链表
void SListDestroy(PNode* pHead)
{
	SListClear(pHead);
}
// 求链表中结点的个数
int SListSize(PNode pHead)
{
	PNode pCur = NULL;
	int count = 0;
     pCur = pHead;
	while (pCur)
	{
		count++;
		pCur = pCur->_pNext;
	}
	return count;
}

//打印链表
void PrintList(PNode pHead)//不需要改变外部指针的指向,所以用一级指针
{
	PNode pCur = pHead;
 	while (pCur)
	{
		printf("%d->", pCur->_data);
		pCur = pCur->_pNext;
	}
	printf("NULL\n");
}
//从尾到头打印单链表
void PrintListFromTail2Head(PNode pHead)
{
	if (pHead)
	{
		PrintListFromTail2Head(pHead->_pNext);
		printf("%d", pHead->_data);
	}
}
//删除无头单链表的非尾结点,要求不能遍历链表 (删除后一个节点,替换到要删除的位置)
//删除pos后一个节点的信息,将后一个节点的值赋给前一个节点,因为不能遍历,所以不能直接删除
void DeleteNotTailNode(PNode pos)
{
	PNode pDelNode = NULL;//保存要删除的位置
	//PNode pDelNode = pos->_pNext;//这样会导致下一步检测pos是否存在没有意义
	if (NULL == pos&&NULL == pos->_pNext)//判断是否存在要删除的位置,是否为尾节点
		return;
	pDelNode = pos->_pNext;
	pos->_data = pDelNode->_data;//把要删除节点下一个节点数据交给前一个
	pos->_pNext = pDelNode->_pNext;
	free(pDelNode);//删除下一个节点
}
//在无头单链表的一个节点前插入一个节点(不能遍历链表):在链表pos位置前插入值为data的结点 
//(插入新节点到pos节点的后面,后交换前一个节点与新节点),数据改变了,但地址未曾改变
//或插入后,直接将前一个节点的值给第二个节点

void InsertPosFront(PNode pos, DataType data)
{
	PNode pNewNode = NULL;
	if (NULL == pos)
		return;
	pNewNode = BuySListNode(pos->_data);
	pNewNode->_pNext = pos->_pNext;
	pos->_pNext = pNewNode;
	pos->_data = data;
}
// 实现约瑟夫环 (1.报数 2、删除节点)
//约瑟夫环指的是:一组数字形成一个环,设置数字m,
//每次读到的第m个数字被删除,循环读取
//1、给定一个约瑟夫环:一串数字组成一个循环
//2、(1)报数;(2)删除节点:方式1:保存pcur的前一个节点pre,让pre节点的next域指向pcur的next域,把pCur放到pcur的next位置上
//                             方式2:把pCur下一个位置的值交给pCur,保存数据,删除下个节点,然后从pCur位置开始下次报数
//接环:next指向空
void JosephCircle(PNode* pHead, const int M)
{
	PNode pCur = NULL;
	PNode pDelNode = NULL;
	assert(pHead);
	if (NULL == *pHead)
		return;
	pCur = *pHead;
  	while (pCur != pCur->_pNext)
	{
		int count = M;
		//报数
		while (--count)
			   pCur = pCur->_pNext;
			//删节点(替换法删除)
			pDelNode = pCur->_pNext;//把pCur下一个位置的值交给pCur
			pCur->_data = pDelNode->_data; //保存数据,
			pCur->_pNext = pDelNode->_pNext;//删除下个节点, 
			free(pDelNode);
		*pHead = pCur;
		return *pHead;
	}
}
//找尾节点(找链表中最后一个节点的位置)
PNode slistBack(PNode pHead)
{
	PNode pCur = pHead;
	if (NULL == pHead)
		return;
	while (pCur->_pNext)
	{
		pCur = pCur->_pNext;
	}
	return pCur;
}
// 使用冒泡方式对单链表进行排序 
void BubbleSort(PNode pHead)
{
	PNode pPreCur = NULL;
	PNode pCur = NULL;
	PNode pTail = NULL;
	if (NULL == pHead || NULL == pHead->_pNext)//为空或者只有一个节点不用排序
		return;
	pPreCur = pHead;
	pCur = pPreCur->_pNext;
	int IsChange = 0;//检验是否已交换成为有序
	while (pCur != pTail)//pTail位于空的位置上
	{
		 
		if ((pPreCur->_data) > (pCur->_data))
		{
			int tmp = pPreCur->_data;
			pPreCur->_data = pCur->_data;
			pCur->_data = tmp;
			IsChange = 1;
		}
		pPreCur = pCur;
		pCur = pPreCur->_pNext;
	}
	if (!IsChange)
		pTail = pPreCur;
}
// 单链表的逆置(交换第一个节点和倒数第一个;法1、倒数第二个和第二个……时间复杂度为n^2)
//法二、借助辅助空间遍历两次
//采用---三个指针:

 
void ReverseSList(PNode* pHead)//需要改变指向,传二级指针
{
	PNode pPre = NULL, pCur = NULL, pNext = NULL;
	assert(pHead);
	if (NULL == *pHead || NULL == (*pHead)->_pNext)//一个节点或者空不用逆置
		return;
	pCur = *pHead;
	while (pCur)
	{
		pNext = pCur->_pNext;
		pCur->_pNext = pPre;
		pPre = pCur;
		pCur = pNext;
	}
	*pHead = pPre;
}
//逆置  头插法
//1、创建一个新链表,pNewNode指向新链表的头节点
//2、pCur的next域指向pNewNode
//3、pcur放到next的位置
PNode ReverseSListOP(PNode pHead)
{
	PNode pNewHead = NULL;
	PNode pCur = NULL;
	PNode pNext = NULL;
	if (NULL == pHead)
		return;
	pCur = pHead;
	while (pCur)
	{
 		pNext = pCur->_pNext;
		pCur->_pNext = pNewHead;
		pNewHead = pCur;//新链表里的第一个节点
		pCur = pNext;
	}
	return pNewHead;
}
//这两个逆置的方法都解决不了代码环的问题,我们可以先将代码环解开,然后逆置,逆置后
//将代码环解开后置空的那个节点与原代码环中的节点连接

// 合并两个有序链表,合并起来依然要有序 
//比较两个链表中节点的大小 ,将小的那个链表中的元素搬到新空间中
//将当前节点较小的那个链表中的节点向后移动一步,继续与另一个链表中的节点进行比较
//循环进行;采用尾插法
PNode MergeSList(PNode pHead1, PNode pHead2)
{
	PNode pNewNode = NULL;
	PNode pTailNode = NULL;
	PNode PL1 = pHead1;
	PNode PL2 = pHead2;
	//if (NULL == pHead1)
	//	return pHead2;
	//if (NULL == pHead2)
	//	return pHead1;
	if (NULL == pHead1 || NULL == pHead2)
		return pHead1 == NULL ? pHead2 : pHead1;
	//两表都不为空
	if (PL1->_data < PL2->_data)
	{
		pNewNode = PL1;
		PL1 = PL1->_pNext;
	}
	else
	{
		pNewNode = PL2;
		PL2 = PL2->_pNext;
	}
	pTailNode = pNewNode;//向新链表中尾插节点
	while (PL1&&PL2)
	{
		if (PL1->_data < PL2->_data)
		{
			pTailNode->_pNext = PL1;
			PL1 = PL1->_pNext;
		}
		else
		{
			pTailNode->_pNext = PL2;
			PL2 = PL2->_pNext;
		}
		pTailNode = pTailNode->_pNext;//已经尾插了新节点,改变pTail指针的指向
	}
	if (PL1)//PL1不为空,还有节点,PL2走到了末尾,把PL2剩下的节点全部挂到后面
		pTailNode->_pNext = PL1;
	else
		pTailNode->_pNext = PL2;
	return pNewNode;
}

// 查找链表的中间结点,要求只能遍历一次链表(块慢指针)
//走的快的(pFast)走两步,走的慢的(pSlow)走一步
//若为奇数个节点,pFast走到空位置的前一个位置(pFast的next为空),pSlow为中间位置
//若为偶数个节点,pFast最终走到空的位置,pSlow为中间节点的位置(两个中间位置的后一个),
//走到倒数第二个位置处;; 
//若需要两个中间位置的前一个,则给一个指针标记中间位置的前一个位置即可
//if(pFast==NULL) return pPre;
PNode FindMiddleNode(PNode pHead)
{
	PNode pFast = pHead;
	PNode pSLow = pHead;
	while (pFast&&pFast->_pNext)
	{
		pFast = pFast->_pNext->_pNext;
		pSLow = pSLow->_pNext;
	}
	return pSLow;
}

// 查找链表的倒数第K个结点,只能遍历一次链表。 (一个指针先走k步后,两个指针一起走:
//快的pFast先朝前走k步,
//k>链表中节点的个数:NULL
//k<=链表中节点的个数:pSlow
PNode FindLastKNode(PNode pHead, int K)
{
	PNode pFast = pHead;
	PNode pSlow = pHead;
	if (NULL == pHead || K <= 0)
		return NULL;
	//让Fast先走k步
	while (K--)
	{
		if (NULL == pFast)//k超过链表中节点的个数
			return NULL;
		pFast = pFast->_pNext;
	}
	//让Fast先走k-1步
	//while (--k)
	//{
	//	if (NULL == pFast->_pNext)//k超过链表中节点的个数
	//		return NULL;
	//	pFast = pFast->_pNext;
	//}
	//两个指针同时往后走,每次走一步
	while (pFast)
	{
		pFast = pFast->_pNext;
		pSlow = pSlow->_pNext;
	}
	return pSlow;
}

//删除倒数第k个节点:
//1、找倒数第k个节点
//2、删除节点(头节点,头删phead指向next;
//非头节点,保存pSlow的前一个节点,pPre指向pFast:用于非空尾节点)


// 判断两个单链表是否相交---链表不带环 
//一、相交
//1、第一个链表的最后一个节点指向第二个链表的最后一个节点:最后一个节点是否相同
//2、第一个链表的最后一个节点指向第二个链表的任意一个节点:判断两个链表的最后一个节点是否相同
//3、第一个链表的最后一个节点指向第二个链表的第一个节点:最后一个节点是否相同
int IsCrossWithoutCircle(PNode pHead1, PNode pHead2)
{
	PNode pTail1 = pHead1;
	PNode pTail2 = pHead2;
	if (NULL == pHead1 || NULL == pHead2)
		return 0;
	//找第一个链表的最后一个节点
	while (pTail1->_pNext)
	{
		pTail1 = pTail1->_pNext;
	}
	//找第二个链表的最后一个节点
	while (pTail2->_pNext)
	{
		pTail2 = pTail2->_pNext;
	}
	return pTail1 == pTail2;
}
// 如果相交 获取交点  
//链表L1与链表L2相交
//1、交点到两个链表的头部的节点数是相同的,同时向后走,则一定会相交
//2、交点到两个链表的头部的节点数是不同的,较长的链表先走(长链表-短链表)步
PNode GetCrossNode(PNode pHead1, PNode pHead2)
{
	int size1 = 0;
	int size2 = 0;
	PNode pCur1 = pHead1, pCur2 = pHead2;
	int gap = 0;
	if (!IsCrossWithoutCircle(pHead1, pHead2))//不相交,则返回
		return NULL;
	//求两个链表中节点的个数
	while (pCur1)//求pCur1的长度
	{
		size1++;
		pCur1 = pCur1->_pNext;
	}
	while (pCur2)//求pCur2的长度
	{
		size2++;
		pCur2 = pCur2->_pNext;
	}
	//让长的链表先朝后走差值步
	gap = size1 - size2;
	pCur1 = pHead1;
	pCur2 = pHead2;
	if (gap > 0)//第一个链表长
	{
		while (gap--)
		{
			pCur1 = pCur1->_pNext;
		}
	}
	else//gap>0
	{
		while (gap++)
		{
			pCur2 = pCur2->_pNext;
		}
	}
	while (pCur1 != pCur2)
	{
		pCur1 = pCur1->_pNext;
		pCur2 = pCur2->_pNext;
	}
	return pCur1;//该位置位交点,否则不相交
}


//判断两个链表是否相交,若相交,求交点(假设链表可能带环)
// 判断链表是否带环 (0,6,9)//给定两个指针一个一次走一步,一个一次走两步,判断是否会相交
//一个走1步,一个走3步,若是只有两个节点则不会相遇(快指针和慢指针的差为节点的个数)
//快指针和慢指针的差不得等于节点的个数
PNode IsCircle(PNode pHead)
{
	PNode pFast = pHead;
	PNode pSlow = pHead;
	while (pFast&&pFast->_pNext)
	{
		pFast = pFast->_pNext->_pNext;//pFast不得为空
		pSlow = pSlow->_pNext;//pFast->_pNext不得为空
		if (pFast == pSlow)
			return pFast;//带环
	}
	return NULL;//不带环
}

// 若带环,求环的长度 
int GetCircleLen(PNode pHead)
{
	PNode pMeetNode = IsCircle(pHead);//判断有没有带环。IsCircle(pHead)返回的为相遇点
	PNode pCur = pMeetNode;
	int count = 1;//因为没有算pMeetNode位置的节点个数,所以count必须从1开始
	if (NULL == pMeetNode)//链表没有带环
		return 0;
	while (pCur->_pNext != pMeetNode)
	{
		count++;
		pCur = pCur->_pNext;
	}
	return count;
}

// 求环的入口点--注意推断过程 
//一个指针从起始点开始,另一个指针从相遇点开始,一次走一步,一定会在入口点相遇
//只要慢指针进环了,快指针可以在一圈之内追上慢指针

 
PNode GetEnterNode(PNode pHead, PNode pMeetNode)
{
	PNode PM = pMeetNode;//从相遇点往后走
	PNode PH = pHead;//从链表起始位置往后走
	if (NULL == pHead || NULL == pMeetNode)//链表和入口点都不能为空
		return NULL;
	while (PH != PM)
	{
		PH = PH->_pNext;
		PM = PM->_pNext;
	}
	return PM;
}

//判断两个链表是否相交,若相交,求交点(假设链表可能带环)
//不带环的相交,还可以构环找交点(交点为入口点):即一个链表尾节点的next域指向另一个节点的开头

 
int IsListCrossWithCircle(PNode pHead1, PNode pHead2)
{
	PNode PMeetNode1 = NULL;
	PNode PMeetNode2 = NULL;
	if (NULL == pHead1 || NULL == pHead2)//避免空链表的存在
		return 0;
	PMeetNode1 = IsCircle(pHead1);
	PMeetNode2 = IsCircle(pHead1);
	//两个链表都不带环
	if (NULL == PMeetNode1&&NULL == PMeetNode2)
		//找两个链表的最后一个节点,检测是否是同一个节点
	{
		PNode pTail1 = pHead1;
		PNode pTail2 = pHead2;
		while (pTail1->_pNext)//空链表也不带环,但是两个都为空,是相等的
			pTail1 = pTail1->_pNext;
		while (pTail2->_pNext)
			pTail2 = pTail2->_pNext;
		if (pTail1 == pTail2)//相交
			return 1;
	}
	//两个链表都带环
	else if (PMeetNode1&&PMeetNode2)//两个相遇点都存在,两个链表均带环
	{
		//让一个相遇点绕环一周,看另外一个相遇点是否存在
		PNode pCur = PMeetNode1;
		do
		{
			if (pCur == PMeetNode2)
				return 2;
			pCur = pCur->_pNext;
		} while (pCur != PMeetNode1);
		 //此过程采用while循环会导致少判断一个节点

	}
	return 0;//一个带环,一个不带环;不相交
}

 
// 复杂链表的复制 
 pComplexListNode CopyComplexList(pComplexListNode pHead)
{
	pComplexListNode pOldNode = pHead;
	pComplexListNode pNewNode = NULL;
	pComplexListNode pNewHead = NULL;
	if (NULL == pHead)
		return NULL;
	//在原链表每个节点后插入值与原链表相同的新节点
	while (pOldNode)
	{
		pNewNode = (pComplexListNode)malloc(sizeof(ComplexListNode));
		if (NULL == pNewNode)
			return NULL;
		pNewNode->data = pOldNode->data;
		pNewNode->pNext = NULL;
		pNewNode->pRandom = NULL;

		pNewNode->pNext = pOldNode->pNext;//插入新节点
		pOldNode->pNext = pNewNode;//断开原链表
		pOldNode = pNewNode->pNext;//oldNode向后移动一步
	}
	//给新插入节点的随机指针域赋值
	pOldNode = pHead;

	while(pOldNode)
	{
		pNewNode = pOldNode->pNext;//新节点的位置
		if (pOldNode->pRandom == NULL) 
			pNewNode->pRandom = NULL;
		else
			pNewNode->pRandom = pOldNode->pRandom->pNext;
		pOldNode = pNewNode->pNext;
	}
	//拆开
	pOldNode = pHead;
	pNewHead = pOldNode->pNext;
	while (pOldNode->pNext)//有节点就不会终止
	{
		pNewNode = pOldNode->pNext;//新节点
		pOldNode->pNext = pNewNode->pNext;//old指向新节点的下一个位置,即断开了
		pOldNode = pNewNode;//oldNode移动一步到newnode处
	}
	return pNewHead;
}
 

test.c
# include"Link.h"
# define _CRT_SECURE_NO_WARNING 1
void Test1()
{
	PNode pHead;
	SListInit(&pHead);
	SListPushBack(&pHead, 1);
	SListPushBack(&pHead, 2);
	SListPushBack(&pHead, 7);
	SListPushBack(&pHead, 9);
	SListPushBack(&pHead, 3);
	PrintList(&pHead);
	SListPopBack(&pHead);
	SListPopBack(&pHead);
	PrintList(&pHead);
}
void Test2()
{
	PNode pHead;
	SListInit(&pHead);
	SListPushFront(&pHead, 2);
	SListPushFront(&pHead, 8);
	SListPushFront(&pHead, 9);
	SListPushFront(&pHead, 0);
	SListPushFront(&pHead, 4);
	PrintList(&pHead);
	SListPopFront(&pHead);
	PrintList(&pHead);
	SListPopFront(&pHead);
	SListPopFront(&pHead);
	SListPopFront(&pHead);
	SListPopFront(&pHead);
	PrintList(&pHead);
}
void Test3()
{
	PNode pHead, pCur;
	SListInit(&pHead);
	SListPushBack(&pHead, 1);
	SListPushBack(&pHead, 2);
	SListPushBack(&pHead, 7);
	SListPushBack(&pHead, 9);
	SListPushBack(&pHead, 3);
	PrintList(pHead);
	pCur = SListFind(&pHead, 7);
	if (pCur)
	{
		SListInsert(&pHead, pCur, 0);
	}
	SListErase(&pHead, pCur);
	PrintList(pHead);
	printf("size=%d\n", SListSize(pHead));
	SListClear(&pHead);
	SListClear(&pHead);
	SListDestroy(&pHead);
}
//测试约瑟夫环
void Test4()
{
	PNode pHead, pCur;
	SListInit(&pHead);
	SListPushBack(&pHead, 1);
	SListPushBack(&pHead, 2);
	SListPushBack(&pHead, 3);
	SListPushBack(&pHead, 4);
	SListPushBack(&pHead, 5);
	SListPushBack(&pHead, 6);
	SListPushBack(&pHead, 7);
	SListPushBack(&pHead, 8);
	PrintList(pHead);
	//建立环
	slistBack(pHead)->_pNext = pHead;
	JosephCircle(pHead, 5);
	//解环
	pHead->_pNext = NULL;
}
void TestBubbleSort()
{
	PNode pHead, pCur;
	SListInit(&pHead);
	SListPushBack(&pHead, 1);
	SListPushBack(&pHead, 2);
	SListPushBack(&pHead, 7);
	SListPushBack(&pHead, 9);
	SListPushBack(&pHead, 3);
	PrintList(pHead);
	BubbleSort(pHead);
	PrintList(pHead);
	SListDestroy(&pHead);
}
void TestReverseList()
{
	PNode pHead;
	SListInit(&pHead);
	SListPushBack(&pHead, 1);
	SListPushBack(&pHead, 2);
	SListPushBack(&pHead, 3);
	SListPushBack(&pHead, 4);
	SListPushBack(&pHead, 5);
	SListPushBack(&pHead, 6);
	SListPushBack(&pHead, 7);
	SListPushBack(&pHead, 8);
	PrintList(pHead);
	ReverseSList(&pHead);
	PrintList(pHead);
}
void TestReverseListOp()
{
	PNode pHead;
	SListInit(&pHead);
	SListPushBack(&pHead, 1);
	SListPushBack(&pHead, 2);
	SListPushBack(&pHead, 3);
	SListPushBack(&pHead, 4);
	SListPushBack(&pHead, 5);
	SListPushBack(&pHead, 6);
	SListPushBack(&pHead, 7);
	SListPushBack(&pHead, 8);
	PrintList(pHead);
	pHead = ReverseSListOP(pHead);
 	PrintList(pHead);
}
void TestMergeList()
{
	PNode pHead1,pHead2;
	SListInit(&pHead1);
	SListPushBack(&pHead1, 1);
	SListPushBack(&pHead1, 2);
	SListPushBack(&pHead1, 3);
	SListPushBack(&pHead1, 4);
	PrintList(pHead1);
	SListInit(&pHead2);
	SListPushBack(&pHead2, 3);
	SListPushBack(&pHead2, 4);
	SListPushBack(&pHead2, 6);
	SListPushBack(&pHead2, 8);
	PrintList(pHead2);
	pHead1=MergeSList(pHead1, pHead2);
	PrintList(pHead1);
	SListDestroy(&pHead1);
}
void TestFindMiddleAndLastKNode()
{
	PNode pHead,pCur=NULL;
	PNode Cur = NULL;
	SListInit(&pHead);
	SListPushBack(&pHead, 1);
	SListPushBack(&pHead, 2);
	SListPushBack(&pHead, 3);
	SListPushBack(&pHead, 4);
	SListPushBack(&pHead, 5);
	SListPushBack(&pHead, 6);
	SListPushBack(&pHead, 7);
	SListPushBack(&pHead, 8);
	PrintList(pHead);
	pCur =FindMiddleNode(pHead);
	printf("中间节点是:%d\n", pCur->_data);
	SListPopBack(&pHead);
	PrintList(pHead);
	pCur = FindMiddleNode(pHead);
	printf("中间节点是:%d\n", pCur->_data);
	Cur = FindLastKNode(pHead, 2);
	if (Cur)
		printf("链表中倒数第%d个节点是:%d\n", 2, Cur->_data);
	else
		printf("倒数第%d个节点不存在\n",2);
	SListDestroy(&pHead);
}
void TestIsSlistCross()
{
	//相交
	//不相交
	PNode pHead1=NULL, pHead2= NULL,pCur;
	SListInit(&pHead1);
	SListPushBack(&pHead1, 1);
	SListPushBack(&pHead1, 2);
	SListPushBack(&pHead1, 3);
	SListPushBack(&pHead1, 4);
	SListPushBack(&pHead1, 5);
	SListPushBack(&pHead2, 6);
	SListPushBack(&pHead2, 7);
	SListPushBack(&pHead2, 8);
	SListPushBack(&pHead2, 9);
	SListPushBack(&pHead2, 0);
	slistBack(pHead1)->_pNext = SListFind(pHead2, 7);
	if (IsCrossWithoutCircle(pHead1, pHead2))
	{
		printf("两个链表相交\n");
		pCur=GetCrossNode(pHead1, pHead2);
		assert(pCur);
		printf("交点为:%d\n", pCur->_data);
	}
 	else
		printf("两个链表不相交\n");
	PrintList(pHead2);

}
void TestIsListCrossWithCircle()
{
	PNode pHead1 = NULL, pHead2 = NULL, pCur;
 	SListPushBack(&pHead1, 1);
	SListPushBack(&pHead1, 2);
	SListPushBack(&pHead1, 3);
	SListPushBack(&pHead1, 4);
	SListPushBack(&pHead1, 5);
	SListPushBack(&pHead1, 6);
	SListPushBack(&pHead1, 7);
	SListPushBack(&pHead1, 8);
 	slistBack(pHead1)->_pNext = SListFind(pHead1, 5);
	SListPushBack(&pHead2, 1);
	SListPushBack(&pHead2, 2);
	SListPushBack(&pHead2, 3);
 	slistBack(pHead2)->_pNext = SListFind(pHead1, 3);
	int ret = IsCrossWithoutCircle(pHead1, pHead2);
	if (1 == ret)
	{
		printf("两个链表不带环相交\n");
	}
	else if (2 == ret)
	{
		printf("两个链表均带环相交\n");
	}
	else
		printf("两个链表不相交\n");
}
void TestCopyComplexList()
{
	ComplexListNode node1, node2, node3, node4;
	pComplexListNode pHead = NULL;
	node1.data = 1;
	node1.pNext = &node2;
	node1.pRandom = &node3;
	node2.data = 2;
	node2.pNext = &node3;
	node2.pRandom = &node1;
	node3.data = 3;
	node3.pNext = &node4;
	node3.pRandom = &node3;
	node4.data = 4;
	node4.pNext = NULL;
	node4.pRandom = NULL;
	pHead = CopyComplexList(&node1);
}
int main()
{
	//Test1();
	//Test2();
	//Test3();
	//Test4();
	//TestBubbleSort();
	//TestReverseList();
	//TestReverseListOp();
	//TestMergeList();
	//TestFindMiddleAndLastKNode();
	//TestIsSlistCross();
	//TestIsListCrossWithCircle();
	TestCopyComplexList();
	system("pause");
	return 0;
}


猜你喜欢

转载自blog.csdn.net/xuruhua/article/details/80417905