1.从尾到头打印单链表
2.在无头单链表的一个节点前插入一个节点
3.单链表实现约瑟夫环
4.逆置/反转单链表
5.单链表排序(冒泡排序&快速排序)
6.合并两个有序链表,合并后依然有序
7.查找单链表的中间节点,要求只能遍历一次链表
8.查找单链表的倒数第k个节点,要求只能遍历一次链表
1.分析
先打印1的子链表再打1,2.3.4同1(递归)
void PrintTailToHead(ListNode* plist)
{
if(plist==NULL)
return;
PrintTailToHead)(plist->next);
printf("%d->",plist->data);
}
//测试
void TestList3()
{
ListNode* List=NULL;
pushback(&List,1);
pushback(&List,2);
pushback(&List,3);
pushback(&List,4);
PrintList(list);
PrintTailToHead(list);
}
2.分析
(1)例如单链表1->2->4->5->,在4节点之前插入一个3节点,只能在节点4后插入,然后和节点4进行交换
(2)1->2->4->,在4节点之前插入一个3节点,用指针来确定位置
void InsertNonHead(ListNode* pos,DataType x)
{
assert(pos);
ListNode* tmp = BuyNode(x);
ListNode* next = pos->next;
pos->next = tmp;
tmp->next = next;
//插入值
DataType tmpData = pos->data;
pos->data = tmp->data;
tmp->data = tmpData;
//交换值
}
3.分析
*约瑟夫环:一圈共有N个人,开始报数,报到M的人自杀,然后重新开始报数,问最后自杀的人是谁?
有N个数,删除第K个数,看剩下的数是多少?
分析:方法一:数组
删除数据并前移余下的数,将删除的数据标记为-1,重新计数
方法二:节点
采用节点删除
ListNode*JosephRing(ListNode* List)
{
if(list == NULL)
//断言:一定不可为空;if:可以为空,用条件判断
return NULL;
ListNode* cur = list;
while(cur->next != cur)
{
int count = k;
while(--count)
//--count:走k-1次;count--:走k次
{
cur = cur->next;
}
ListNode* next = cur->next;
cur->next = next->data;
cur->next = next->next;
free(next);
}
}
//
void TestList4()
{
ListNode* List=NULL;
pushback(&List,1);
pushback(&List,2);
pushback(&List,3);
pushback(&List,4);
PrintList(list);
}
ListNode* pos = Find(list,4);//变成环
pos->next = list;
ListNode* last = JosephRing(list,3);
printf("幸存者:%d\n",last->data);
//解环,置空
free(last);
list = last = NULL;
4.分析
采用头插的方法
ListNode* Reverse(ListNode* list)
{
ListNode* newlist = NULL;
ListNode* cur = list;
//当cur为空时则证明全部逆置结束
while(cur)
{
ListNode* tmp = cur;
cur = cur->next;//摘节点
tmp->next = newlist;
newlist = tmp;//插节点
}
return newlist;
}
5.分析:
a.next=NULL
b.使用tail指针控制终止位置:next=tail
void BubbleSort(ListNode* list)
{
if(list == NULL || list->next == NULL)
{
return;
}
ListNode* tail = NULL;
while(tail!=list->next)
int exchange = 0;
{
ListNode* cur = list;
ListNode* next = cur->next;
while(next!=tail)
{
if(cur->data > next->data)
{
DataType tmp = cur->data;
cur->data = next->data;
next->data = tmp;
}
cur = cur->next;
next = next->next;
}
if(exchange == 0)
{
break;
}
tail = cur;
}
}
6.分析:
第一个数头插,其余尾插
ListNode* Merge(ListNode* list1,ListNode* list2)
{
if(list1 == NULL)
{
return list2;
}
if(list2 == NULL)
{
return list1;
}
//先摘一个节点做头
ListNode* list = NULL;
if(list->data < list1->data)
//判断链表1和链表2中头小的那个,默认为2比1小
{
list = list2;
list2 = list2->next;
}
else
{
list = list1;
list1 = list1->next;
}
//尾插
ListNode* tail = list;
while(list1&&list2)
{
if(list1->data < list2->data)
{
tail->next = list1;
list1 = list1->next;
}
else
{
tail->next = list2;
list2 = list2->next;
}
tail = tail->next;
}
//
if(list1)
tail->next = list1;
else
tail->next = list2;
return list;
}
7.分析:
采用快慢指针,中间节点有两种情况;如果是奇数个节点的话取中间节点;如果有偶数个节点则由奇数的结果决定。fast一次走两步,slow一次走一步当fast指向空时,此时slow指向中间节点。
ListNode* FindMidNode(ListNode* list)
{
if(list == NULL)
return NULL;
ListNode* slow = list;
ListNode* fast = list;
while(fast&&fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
8.分析:
fast先走k-1步后,(fast和slow相差k-1)fast和slow再同时走,fast走一步,slow走一步。当fast走向尾节点时,则slow指向倒数第k个;
fast先走k步后同上,当fast=NULL时,slow为倒数第k个
ListNode* FindTail_k_Node(ListNode* list,int K)
{
ListNode* slow = list;
ListNode* fast = list;
while(k--)
{
return NULL;
fast = fast->next;
}
while(fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}