2.删除一个无头单链表的非尾节点
3.在无头单链表的一个节点前插入一个节点
4.单链表实现约瑟夫环
5.逆置/反转单链表
6.单链表排序(冒泡排序)
7.合并两个有序链表,合并后依然有序
8.查找单链表的中间节点,要求只能遍历一次链表
9.查找单链表的倒数第k个节点,要求只能遍历一次链表
函数如下:
typedef int DataType;
typedef struct ListNode
{
DataType data;
ListNode* next;
}ListNode;
void PrintList_r(ListNode* pplist); //1.逆序打印
void EraseNonTail(ListNode* pos); //2.删除一个无头单链表的非尾节点
void InsertNonHead(ListNode* pos, DataType data); //3.在无头单链表的一个节点前插入一个节点
ListNode* JosephRing(ListNode* plist, int k); //4.约瑟夫环,数到k删掉(参数是一个循环链表)
ListNode* ReverseList(ListNode* plist); //5.单链表逆序存储(摘节点)
void BubbleList(ListNode* plist); //6.冒泡排序
ListNode* CombineList(ListNode* plist1, ListNode* plist2); //7.合并两个有序链表,合并后依然有序
ListNode* SearchListMid(ListNode* plist); //8.查找中间节点(偶数个节点返回靠后的中间节点)
ListNode* SearchListK_r(ListNode* plist, int k); //9.查找单链表的倒数第k个节点,要求只能遍历一次链表
1.从尾到头打印单链表
思路:递归
void PrintList_r(ListNode* plist)
{
if (plist == NULL)
{
return;
}
PrintList_r (plist -> next);
printf("%d->", plist -> data);
}
2.删除一个无头单链表的非尾节点
思路:交换当前节点和下一个节点的值,释放掉下一个节点
void EraseNonTail(ListNode* pos)
{
assert(pos && pos->next);
ListNode* next = pos->next;
pos->data = next->data;
pos->next = next->next;
free(next);
}
3.在无头单链表的一个节点前插入一个节点
思路:在该位置后面插入一个节点,并与该节点交换值
void InsertNonHead(ListNode* pos, DataType data)
{
assert(pos);
ListNode* next = pos->next;
ListNode* tmp = BuyNode(data);
pos->next = tmp;
tmp->next = next;
DataType datatmp = pos->data;
pos->data = tmp->data;
tmp->data = datatmp;
}
4.单链表实现约瑟夫环
思路:每次数到k的时候删除该节点,直到只剩一个,并返回该节点
ListNode* JosephRing(ListNode* plist, int k)
{
//如果不带环返回空指针,判断是否带环的函数进阶篇有写
if(IsCycle(plist) == NULL)
{
return NULL;
}
ListNode* cur = plist;
//只剩一个节点循环停止
while(cur != cur->next)
{
int count = k;
while(--count) //例如k为3的时候,只用走2步
{
cur = cur->next;
}
//替换法删除
ListNode* next = cur->next;
cur->data = next->data;
cur->next = next->next;
free(next);
}
return cur;
}
5.逆置单链表
思路:创建一个新的头指针,用cur和tmp摘节点,每次把原链表的头结点指向新的头结点
ListNode* ReverseList(ListNode* plist)
{
ListNode* newhead = NULL;
ListNode* cur = plist;
ListNode* tmp = plist;
while(cur)
{
cur = cur->next;
tmp->next = newhead;
newhead = tmp;
tmp = cur;
}
return newhead;
}
6.单链表排序(冒泡排序)
单趟:用cur和next控制,符合条件则交换,当next走到NULL时第一趟结束
多趟:用tail标记链表尾部,当tail为第二个节点时,交换全部完成
void BubbleList(ListNode* plist)
{
ListNode* tail = NULL;
while(tail != plist->next)
{
ListNode* cur = plist;
ListNode* next = plist->next;
while(next != tail)
{
if(cur->data > next->data)
{
DataType tmp = cur->data;
cur->data = next->data;
next->data = tmp;
}
next = next->next;
cur = cur->next;
}
tail = cur;
}
}
7.合并两个有序链表,合并后依然有序
思路:定义一个新的头指针,一开始指向plist1和plist2首元素较小的那个,然后依次遍历两个链表,每次把较小的值加到新头指针list的后面
ListNode* CombineList(ListNode* plist1, ListNode* plist2)
{
ListNode* list = NULL;
if(plist1 == NULL)
{
return plist2;
}
else if(plist2 == NULL)
{
return plist1;
}
else
{
if(plist1->data < plist2->data)
{
list = plist1;
plist1 = plist1->next;
}
else
{
list = plist2;
plist2 = plist2->next;
}
ListNode* tail = list;
while (plist1 && plist2)
{
if(plist1->data < plist2->data)
{
tail->next = plist1;
plist1 = plist1->next;
tail = tail->next;
}
else
{
tail->next = plist2;
plist2 = plist2->next;
tail = tail->next;
}
}
if(plist1 == NULL)
{
tail->next = plist2;
}
else
{
tail->next = plist1;
}
}
return list;
}
8.查找单链表的中间节点,要求只能遍历依次链表
思路:快慢指针,每次快指针走2步,慢指针走1步
1.链表有奇数个节点,快指针指向最后一个节点,慢指针则指向中间节点
2.链表有偶数个节点,快指针指向空(tail->next),慢指针则指向两个中间节点靠后的那一个
ListNode* SearchListMid(ListNode* plist)
{
ListNode* fast = plist;
ListNode* slow = plist;
while (fast && fast->next)
{
fast = (fast->next)->next;
slow = slow->next;
}
return slow;
}
9.查找单链表的倒数第k个节点,要求只能遍历依次链表
思路:快慢指针,快指针先走k-1步,然后快慢指针一起一步一步的走,当快指针走到尾节点时,慢指针则指向倒数第k个节点
ListNode* SearchListK_r(ListNode* plist, int k)
{
ListNode* fast = plist;
ListNode* slow = plist;
//fast往后走k-1步
int i = k;
for(i=0; i<k-1; i++)
{
fast = fast->next;
//如果k大于了链表长度,返回空指针
if(fast == NULL)
{
return NULL;
}
}
//让fast走到最后一个节点
while(fast->next)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}