从尾到头打印单链表:
递归
void SListPrintBack(PNode pHead) //时间复杂度O(N)
{
if (pHead)
{
SListPrintBack(pHead->_pNext);
printf("%d ", pHead->_Data);
}
}
删除一个无头单链表的非尾节点(不能遍历链表):
找到要删除节点的下一个节点,将它的值付给要删除的结点,删除下一个节点
void EraseNotTail(PNode pos) //替换法删除
{
PNode pDel = NULL;
if (NULL == pos)
{
printf("error! not found %d!\n", pos->_Data);
return;
}
pDel = pos->_pNext; //pos的后一个节点
pos->_Data = pDel->_Data; //赋值
pos->_pNext = pDel->_pNext;
free(pDel);
}
在无头单链表的一个节点前插入一个节点(不能遍历链表):
在该节点后插入一个新节点,将值交换
void InsertFront(PNode pos, DataType data)
{
PNode pNewNode = NULL;
if (NULL == pos)
{
printf("error! not found %d!\n", pos->_Data);
return;
}
pNewNode = BuySListNode(pos->_Data);//直接创建一个值和pos一样的新节点,省去swap
pNewNode->_pNext = pos->_pNext; //链接
pos->_pNext = pNewNode;
pos->_Data = data; //直接将data赋值给pos
}
单链表实现约瑟夫环(JosephCircle)
1.构建环
2.获取M
3.报数----删结点----循环
void JosephCircle(PNode *ppHead, int Step)
{
PNode pDel = NULL;
PNode pCur = NULL;
assert(ppHead);
pCur = *ppHead;
while (pCur->_pNext != pCur) //只剩一个元素
{
//报数
int count = Step;
while (--count) //移动step-1次
{
pCur = pCur->_pNext;
}
//删除(替换法删除,删除后一个节点)
pDel = pCur->_pNext;
pCur->_Data = pDel->_Data;
pCur->_pNext = pDel->_pNext;
free(pDel); //最后会被销毁,可以不置空
}
*ppHead = pCur; //只剩最后一个节点
}
逆置/反转单链表
三个指针法
头插法(新节点,旧的头结点next置空)
void ReverseSList(PNode *ppHead) //三指针法
{
PNode pPreCur = NULL;
PNode pCur = NULL;
PNode pCurTail = NULL;
assert(ppHead);
if (NULL == *ppHead && NULL == (*ppHead)->_pNext)
{
return;
}
pCur = *ppHead;
while (pCur) // p1 p2 p3
{
pCurTail = pCur->_pNext; //p3 = p2->next
pCur->_pNext = pPreCur; //p2->next = p1、断开
pPreCur = pCur; //p1 = p2;
pCur = pCurTail; //p2 = p3
}
*ppHead = pPreCur; //更新头结点
}
PNode ReverseSList2(PNode pHead) //新节点头插法
{
PNode pCur = pHead;
PNode pCurNext = NULL;
PNode pNewHead = NULL;
while (pCur)
{
pCurNext = pCur->_pNext;
pCur->_pNext = pNewHead;
pNewHead = pCur;
pCur = pCurNext;
}
return pNewHead;
}
void ReverseSList3(PNode *ppHead) //头插法
{
//标记头结点的下一个节点
//将其插入到头结点之前
PNode pCur = NULL;
PNode pCurNext = NULL;
assert(ppHead);
pCur = (*ppHead)->_pNext; //标记头结点的后一个节点
(*ppHead)->_pNext = NULL; //将头结点的Next域置空
while (pCur)
{
pCurNext = pCur->_pNext; //标记待头插的结点的下一个节点,防止找不到
pCur->_pNext = *ppHead; //头插
*ppHead = pCur;
pCur = pCurNext;
}
}
单链表排序(冒泡排序)
冒泡排序(三指针、pcur pnext ptail)
void BubbleSort(PNode pHead)
{
PNode pCur = NULL;
PNode pNext = NULL;
PNode pTail = NULL; //尾结点
int flag = 0;
if (NULL == pHead || NULL == pHead->_pNext) //空链表或只有一个结点
{
return;
}
while (pHead != pTail) //控制循环次数
{
flag = 0;
pCur = pHead;
pNext = pCur->_pNext;
while (pNext != pTail) //每一次循环
{
if (pCur->_Data > pNext->_Data)
{
DataType tmp = pCur->_Data;
pCur->_Data = pNext->_Data;
pNext->_Data = tmp;
flag = 1;
}
pCur = pCur->_pNext;
pNext = pCur->_pNext;
}
if (!flag) //未发生交换
{
return;
}
pTail = pCur; //将循环控制的尾指针向前移动
}
}
合并两个有序链表,合并后依然有序
定义新的头结点,依次从两个链表找到较小(大)的,链接到新的链表上即可
PNode MergeList(PNode pHead1, PNode pHead2)
{
PNode pNewHead = NULL;
PNode pTail = NULL; //连接最后没连接完的链表
PNode pNode1 = pHead1; //第一个链表的指针
PNode pNode2 = pHead2; //第二个链表的指针
if (NULL == pHead1 || NULL == pHead2) //有一个空链表
{
return (pHead1) ? pHead1 : pHead2;
}
if (pNode1->_Data < pNode2->_Data) //将头结点和值较小链表的头结点先连接起来
{
pNewHead = pNode1;
pTail = pNode1;
pNode1 = pNode1->_pNext;
}
else
{
pNewHead = pNode2;
pTail = pNode2;
pNode2 = pNode2->_pNext;
}
while (pNode1 && pNode2) //两个链表都未插完
{
if (pNode1->_Data < pNode2->_Data) //将值较小的插入
{
pTail->_pNext = pNode1;
pNode1 = pNode1->_pNext;
}
else
{
pTail->_pNext = pNode2;
pNode2 = pNode2->_pNext;
}
pTail = pTail->_pNext; //尾指针向后移动
}
if (pNode1) //第一个链表未插完
{
pTail->_pNext = pNode1;
}
if (pNode2) //第二个链表未插完
{
pTail->_pNext = pNode2;
}
return pNewHead;
}
查找单链表的中间节点,要求只能遍历一次链表
快慢指针
PNode FindMidNode(PNode pHead) //快慢指针
{
PNode pFast = pHead;
PNode pSlow = pHead;
PNode pPreSlow = NULL;
if (NULL == pHead)
{
return NULL;
}
while(pFast && pFast->_pNext) //奇数个(fast->next 为空)、偶数个(fast为空)
{
pPreSlow = pSlow;
pSlow = pSlow->_pNext; //走一次
pFast = pFast->_pNext->_pNext; //走两次
}
if (pFast)
{
return pSlow;
}
else
{
return pPreSlow; //偶数个返回前一个节点
}
// return pSlow; //偶数个节点时返回后一个节点
}
查找单链表的倒数第k个节点,要求只能遍历一次链表
快指针先走K步,然后快慢指针一起走
PNode FindLastKNode(PNode pHead, int K)
{
PNode pFast = pHead;
PNode pSlow = pHead;
if (NULL == pHead || 0 == K)
{
return NULL;
}
//让快指针先走K步
while (K--)
{
if (NULL == pFast)
return NULL;
pFast = pFast->_pNext;
}
//快慢指针一起走,快指针为空时停止
while (pFast)
{
pFast = pFast->_pNext;
pSlow = pSlow->_pNext;
}
return pSlow;
}
删除链表的倒数第K个结点
找到第K个节点(头结点,非头结点),借助pre指针删除
int DeleteLastKNode(PNode *ppHead, int K)
{
PNode pFast = NULL;
PNode pPreSlow = NULL;
PNode pSlow = NULL;
assert(ppHead);
if (NULL == *ppHead || 0 == K)
{
return 0;
}
pFast = *ppHead;
pSlow = *ppHead;
//快指针先走K步
while (K--)
{
if (NULL == pFast) //快指针走的步数必须小于K
{
return 0;
}
pFast = pFast->_pNext;
}
//快慢指针一起走
while (pFast)
{
pPreSlow = pSlow;
pSlow = pSlow->_pNext;
pFast = pFast->_pNext;
}
if (*ppHead == pSlow) //删头结点
{
*ppHead = pSlow->_pNext;
}
else //非头结点
{
pPreSlow->_pNext = pSlow->_pNext;
}
free(pSlow);
return 1;
}
判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算
每个算法的时间复杂度&空间复杂度。
快慢指针()
环的长度: 先判断带环
环的入口点:
结论:PL-----1-------PHead一次走一步
PM----1------相遇点
If(PL == PM) 入口点二者的相遇点即是入口点
1.两个指针一个从Head处走一个从Meet处走,相遇即为相遇点
2.在快慢指针相聚点截断,将环链表变为两个相交链表,因为相交链表尾部重合呈Y字型,
// 求两个链表长度之差K,再令一个指针从长链表开始先走K步,令另一个指针从短链表头开始,
// 两链表一起走,相遇点就为入口点
PNode HasCircle(PNode pHead)
{
PNode pFast = pHead;
PNode pSlow = pHead;
while (pFast && pFast->_pNext)
{
pFast = pFast->_pNext->_pNext; //快指针一次走两步
pSlow = pSlow->_pNext;
if (pFast == pSlow) //判断是否相遇
{
return pFast;
}
}
return NULL;
}
int GetCircleLen(PNode pHead) //环的大小
{
PNode pCur = NULL;
int size = 1; //计算大小时 会少计算meet的前一个节点
PNode MeetNode = HasCircle(pHead);
if (NULL == MeetNode)
{
return 0;
}
pCur = MeetNode;
while (pCur->_pNext != MeetNode) //从meetNode开始计算
{
size++;
pCur = pCur->_pNext;
}
return size;
}
PNode GetEnterNode(PNode pHead, PNode pMeetNode) //入口点
{
PNode pH = pHead; //从头结点
PNode pM = pMeetNode;
if (pH == NULL || pM == NULL)
{
return NULL;
}
while (pM != pH)
{
pM = pM->_pNext;
pH = pH->_pNext;
}
return pM;
}
判断两个链表是否相交,若相交,求交点。(假设链表不带环):
直接看两个链表的最后一个结点(判断相交)
分别计算两条链表的长度,让长得一个先走差值步,然后一起走,最后走到相同的位置即为交点
int IsCrossWithoutCircle(PNode pHead1, PNode pHead2)
{
PNode pTail1 = pHead1;
PNode pTail2 = pHead2;
if (NULL == pHead1 || NULL == pTail2)
{
return 0;
}
while (pTail1->_pNext)
{
pTail1 = pTail1->_pNext;
}
while (pTail2->_pNext)
{
pTail2 = pTail2->_pNext;
}
return pTail1 == pTail2;
}
PNode GetCrossNode(PNode pHead1, PNode pHead2) //交点
{
int size1 = 0;
int size2 = 0;
PNode pCur1 = NULL;
PNode PCur2 = NULL;
int k = 0;
if (NULL == pHead1 || NULL == pHead2)
{
return NULL;
}
if (!IsCrossWithoutCircle(pHead1, pHead2))
{
return 0;
}
size1 = SListSize(pHead1);
size2 = SListSize(pHead2);
k = size1 - size2;
if (k > 0) //长的先走长度差值步
{
while (k--)
{
pCur1 = pCur1->_pNext;
}
}
else
{
while (k++) //从负值++
{
PCur2 = PCur2->_pNext;
}
}
while (pCur1 != PCur2) //两指针一起走 //肯定有交点最后一定相遇
{
pCur1 = pCur1->_pNext;
PCur2 = PCur2->_pNext;
}
return pCur1;
}
判断两个链表是否相交,若相交,求交点。(假设链表可能带环)
1.两个链表都不带环
2.两个链表都带环
3.一个带一个不带
求交点
环内相交:
任一环内结点为交点
环外相交:
从任意相遇点的位置开始的计算两个链表的长度,(转换成无环相交)
从相遇点断开,链接链表的头结点,构成新的环,求环入口点,完成后恢复原来链表的状态
复杂链表的复制。一个链表的每个节点,有一个指向next指针指向
下一个节点,还有一个random指针指向这个链表中的一个随机节点
或者NULL,现在要求实现复制这个链表,返回复制后的新链表。
1.在原链表每个节点后插入值与当前结点相同的新节点
2.给新节点的随机指针域赋值----原链表当前结点随机指针域的Next
3.将新节点从原链表中拆下