1.从尾到头打印单链表
思路:用两个指针来控制打印:
①tail先指向NULL,然后指针cur从头往后走,走到tail前一个位置,就是最后一个节点,打印这个节点。
②tail往前走,tail指向链表最后一个节点,再让cur走到tail前一个位置,打印。
………….
void SListPrintTailToHead(SListNode* pHead) //从尾到头打印单链表
{
SListNode* tail = NULL;
SListNode* cur = NULL;
while (tail != pHead)
{
cur = pHead;
while (cur->_next != tail)
{
cur = cur->_next;
}
printf("%d ", cur->_data);
tail = cur;
}
}
2.删除一个无头单链表的非尾节点(不能遍历链表)
思路:找到我们可以找到pos的下一个节点,把pos下一个节点的值给pos,再删除pos->next。这样就相当于删除了pos。
void SListRemove(SListNode* pos)
{
assert(pos != NULL && pos->_next != NULL);
SListNode* next = pos->_next;
pos->_data = next->_data;
pos->_next = next->_next;
next->_next = NULL;
free(next);
}
3.在无头单链表的一个节点前插入一个节点(不能遍历链表)
思路:在pos后面插入一个节点newNode,它的数据域放的是pos->_data,然后把pos-> _data改成x,这样就相当于在pos前面插入一个值为x的节点
void SListInsert2(SListNode* pos, DataType x)//在无头单链表的一个节点前插入一个节点(不能遍历链表)
{
assert(pos != NULL);
SListNode* tail = pos->_next;
SListNode* newNode = BuySListNode(pos->_data);
newNode->_next = pos->_next;
pos->_next = newNode;
pos->_data = x;
}
4.单链表实现约瑟夫环(JosephCircle)
思路:先把链表连接成环,从1数到k,其实是往前移动k-1次,然后删除第k个链表。当链表只剩下最后一个节点时,循环结束。
SListNode* JosephCircle(SListNode* pHead, DataType k)
{
SListNode* cur = pHead;
SListNode* next;
while (cur->_next != cur)
{
DataType count = k;
while (--count) //k-1次循环
{
cur = cur->_next;
}
next = cur->_next;
cur->_data = next->_data;
cur->_next = next->_next;
free(next);
}
return cur;
}
5.逆置/反转单链表
思路:定义三个结构体指针进行操作
注意:①开始之前把n1->_next = NULL 。②循环结束的条件
/* 方法一 */
SListNode* ReverseList(SListNode* list)//逆置/反转单链表
{
SListNode* n1, *n2, *n3;
if (list == NULL || list->_next == NULL)
{
return list;
}
n1 = list;
n2 = n1->_next;
n3 = n2->_next;
n1->_next = NULL;
while (n2 != NULL)
{
n2->_next = n1;
n1 = n2;
n2 = n3;
if (n3 != NULL)
{
n3 = n3->_next;
}
}
return n1;
}
/* 方法二 */
SListNode* ReverseList2(SListNode* list)
{
SListNode* newNode = NULL;
SListNode* cur = list;
while (cur != NULL)
{
SListNode* next = cur->_next;
cur->_next = newNode;
newNode = cur;
cur = next;
}
return newNode;
}
6.单链表排序(冒泡排序&快速排序)
冒泡排序
void SListBubbleSort(SListNode* list) //冒泡排序
{
SListNode* tail = NULL;
while (tail != list)
{
int flag = 0;
SListNode* cur = list;
SListNode* next = list->_next;
while (next != tail)
{
if (cur->_data > cur->_next->_data)
{
flag = 1;
DataType tem = cur->_data;
cur->_data = cur->_next->_data;
cur->_next->_data = tem;
}
cur = cur->_next;
next = next->_next;
}
if (0 == flag)
{
return;
}
tail = cur;
}
}
7.合并两个有序链表,合并后依然有序
递归法:
SListNode* MergeSList(SListNode* pHead1, SListNode* pHead2)
{
if (NULL == pHead1)
{
return pHead2;
}
else if (NULL == pHead2)
{
return pHead1;
}
SListNode* newMergeListHead = NULL;
if (pHead1->_data < pHead2->_data)
{
newMergeListHead = pHead1;
newMergeListHead->_next = MergeSList(pHead1->_next, pHead2);
}
else
{
newMergeListHead = pHead2;
newMergeListHead->_next = MergeSList(pHead1, pHead2->_next);
}
return newMergeListHead;
}
/*非递归*/
SListNode* MergeSList(SListNode* pHead1, SListNode* pHead2)
{
if (NULL == pHead1)
{
return pHead2;
}
else if (NULL == pHead2)
{
return pHead1;
}
SListNode* newMergeListHead = NULL;//把排序好的链表存到这里面
SListNode* tail = NULL; //记录新链表最后一个节点
if (pHead1->_data < pHead2->_data)
{
newMergeListHead = pHead1;
pHead1 = pHead1->_next;
}
else
{
newMergeListHead = pHead2;
pHead2 = pHead2->_next;
}
tail = newMergeListHead; //确定好第一个结点
while (pHead1 != NULL && pHead2 != NULL)
{
if (pHead1->_data < pHead2->_data)
{
tail->_next = pHead1;
pHead1 = pHead1->_next;
}
else
{
tail->_next = pHead2;
pHead2 = pHead2->_next;
}
tail = tail->_next;
}
if (NULL == pHead1)
{
tail->_next = pHead2;
}
else if (NULL == pHead2)
{
tail->_next = pHead1;
}
return newMergeListHead;
}
8.查找单链表的中间节点,要求只能遍历一次链表
思路:定义两个指针,一个快指针,一个慢指针。快指针一次走两步,慢指针一次走一步。当快指针走到尾节点时,慢指针刚好走到中间节点。
注意:所有快慢指针题必须主要循环结束的条件。
SListNode* FindMidNode(SListNode* list) // 遍历一遍找到链表中间节点
{
assert(list != NULL);
SListNode* pFast = list;
SListNode* pSlow = list;
while (pFast != NULL && pFast->_next!= NULL)
{
pFast = pFast->_next->_next;
pSlow = pSlow->_next;
}
return pSlow;
}
9.查找单链表的倒数第k个节点,要求只能遍历一次链表。
思路:快慢指针法,首先pFast和pSlow都指向第一个节点,然后让pFast先往前走k-1步,最后pFast和pSlow同时走,当pFast走到最后一个节点时,pSlow走到倒数第k个节点
SListNode* FindReciprocalNode(SListNode* list, size_t k) //遍历一遍查找倒数第K个节点
{
assert(list != NULL && k != 0);
SListNode* pFast = list;
SListNode* pSlow = list;
while (pFast->_next != NULL)
{
k--;
if (k <= 0) //当pFast走到正数第K个节点时,pSlow开始走
{
pSlow = pSlow->_next;
}
pFast = pFast->_next;
}
if (k <= 1) //查找成功时,k的最大值是1(当k=链表长度时)
{
return pSlow;
}
else //大于1代表查找失败
{
return NULL;
}
}
10.删除链表的倒数第K个结点
void RemoveReciprocalNode(SListNode* list, int k) //遍历一遍删除倒数第K个节点
{
assert(list != NULL && k != 0);
SListNode* pFast = list;
SListNode* pSlow = list;
while (pFast->_next != NULL)
{
k--;
pFast = pFast->_next;
if (k <= 0) //当pFast走到正数第K个节点时,pSlow开始走
{
pSlow = pSlow->_next;
}
}
if (k <= 1) //查找成功时,k的最大值是1(当k=链表长度时)
{
SListRemove(pSlow); //用函数:删除一个无头单链表的非尾节点
}
}