一、题目
1、从尾到头打印单链表 (有四种方法)
2、删除一个无头单链表的非尾节点(不能遍历链表)
3、在无头单链表的一个节点前插入一个节点(不能遍历链表)
4、单链表实现约瑟夫环(JosephCircle)
5、逆置/反转单链表
6、单链表排序(冒泡排序&快速排序)
7、合并两个有序链表,合并后依然有序
8、查找单链表的中间节点,要求只能遍历一次链表
9、查找单链表的倒数第k个节点,要求只能遍历一次链表
10、删除链表的倒数第K个结点
二、各函数代码和运行结果
1、从尾到头打印单链表 (有四种方法)
void EndToFirstPrintNode(SListNode*ps) //正常从头到尾打印
{
SListNode *cur=NULL;
SListNode *tail=NULL;
while (ps != tail)
{
cur=ps;
while (tail != cur->_next)
cur=cur->_next;
printf("%d ",cur->_data);
tail=cur;
}
}
void EndToFirstPrintSListNode(SListNode *ps) //链表的从尾到头打印,用动态顺序表保存数据。
{
size_t i = 0;
while (ps)
{
CheckFullSeqlist(&List);
List.data[i++]=ps->_data;
List.size++;
ps=ps->_next;
}
PrintSList(&List);
}
void EndToFirstPrintSListNodeR(SListNode *ps)//递归打印
{
if (NULL != ps->_next) //递归结束条件
EndToFirstPrintSListNodeR(ps->_next); //子问题
printf("%d ",ps->_data);
}
void EndToFirstPrintSListNodeNon(SListNode *ps) //逆置链表
{
SListNode *prev;
SListNode *cur;
SListNode *tmp;
cur=ps; //保存头结点
prev=cur->_next; //保存下一个节点
cur->_next=NULL; //头结点变为尾节点,next=NULL
while (NULL != prev)
{
tmp=prev->_next;
prev->_next=cur;
cur=prev;
prev=tmp;
}
ps=cur; //尾节点变为头节点
SListPrint(ps); //打印链表
}
运行结果:
2、删除一个无头单链表的非尾节点(不能遍历链表)
void NoHeadSeqListDelete(SListNode *pos) //删除一个无头链表的非尾节点(不能遍历链表)
{
SListNode*tmp;
assert(pos);
tmp=pos->_next; //保存pos->_next的值,方便一会销毁
pos->_data=pos->_next->_data;
pos->_next=pos->_next->_next;
free(tmp); //销毁pos->_next
tmp=NULL;
}
运行结果:
3、在无头单链表的一个节点前插入一个节点(不能遍历链表)
//创建一个新节点,替换原来的插入节点的值,再把插入值赋给原节点
void NoHeadSeqListInsert(SListNode*pos,DataType x) //在无头链表的一个节点前插入一个节点(不能遍历链表)
{
SListNode *newNode;
newNode=BuySListNode(x); //创建新节点
newNode->_next=pos->_next;
pos->_next=newNode;
newNode->_data=pos->_data;
pos->_data=x;
}
运行结果:
4、单链表实现约瑟夫环(JosephCircle)
void JosephCircle(SListNode*ps) //约瑟夫环问题
{
int k = 0;
SListNode *tmp=ps;
SListNode*cur=NULL;
while (tmp->_next)
{
tmp=tmp->_next;
}
tmp->_next=ps; //链接为一个环
while (ps!=ps->_next)
{
ps=ps->_next;
k++;
if (k==2) //每走三步杀一个
{
cur=ps->_next;
ps->_next=ps->_next->_next;
k=0;
free(cur);
cur=NULL;
}
}
printf("%d\n",ps->_data);
}
运行结果:
5、逆置/反转单链表
SListNode* ReverseSeqList(SListNode *Seq) //逆置/反转单链表
{
SListNode *prev=Seq; //保存头节点
SListNode *cur=prev->_next; //保存第二个节点
SListNode *tmp;
assert(Seq);
prev->_next=NULL; //置空头节点的next,变成尾节点
while (cur!=NULL) //循环逆置
{
tmp=cur->_next;
cur->_next=prev;
prev=cur;
cur=tmp;
}
Seq=prev; //逆置后的头
return Seq;
}
运行结果:
6、单链表排序(冒泡排序)
void SeqListSort(SListNode *Seq)//单链表排序(冒泡排序)
{
SListNode *tail,*tmp=Seq;
DataType flag=0;
assert(Seq);
if (Seq->_next==NULL||Seq==NULL) //防止是空链表或者只有一个节点
{
return;
}
while (tmp!=NULL) //找尾节点
{
tmp=tmp->_next;
}
tail=tmp;
while (tail!=Seq)
{
tmp=Seq; //重置头节点
while (tmp->_next!=tail)
{
if (tmp->_data>tmp->_next->_data) //循环冒泡
{
flag=1;
tmp->_data^=tmp->_next->_data;
tmp->_next->_data^=tmp->_data;
tmp->_data^=tmp->_next->_data;
}
tmp=tmp->_next; //循环后移
}
if (flag==0) //优化冒泡次数
{
break;
}
tail=tmp; //尾前移
}
}
7、合并两个有序链表,合并后依然有序
SListNode* SListMerge(SListNode *list1,SListNode *list2)//合并两个有序链表,合并后依然有序
{
SListNode *list,*tmp;
assert(list1&&list2);
if (list1->_data<list2->_data) //找到两个链表中小的一个头节点
{
list=list1;
list1=list1->_next;
}
else
{
list=list2;
list2=list2->_next;
}
tmp=list; //将小的一个链表头节点作为新链表的节点
while (NULL!=list1 && NULL!=list2) //循环比较,取两链表中小的节点链给list
{
if (list1->_data<list2->_data)
{
list->_next=BuySListNode(list1->_data); //
list1=list1->_next;
list=list->_next;
}
else
{
list->_next=BuySListNode(list2->_data);
list2=list2->_next;
list=list->_next;
}
}
if (NULL==list1) //取出剩下一个量表后面所有连接给list
{
list->_next=list2;
}
else
{
list->_next=list1;
}
return tmp; //返回新链表的头节点地址
}
运行结果:
8、查找单链表的中间节点,要求只能遍历一次链表
SListNode* SListFindMidNode(SListNode* list) //查找单链表的中间节点,要求只能遍历一次链表
{
SListNode *fast;
SListNode *slow;
assert(list);
fast=slow=list;
//如果链表没节点,一个或者两个节点,直接返回头节点
if (NULL==list || NULL==list->_next || NULL==list->_next->_next)
{
return list;
}
while (fast) //快指针走到尾,慢指针走到中间。
{
fast=fast->_next->_next; //快指针一次走两步
slow=slow->_next; //慢指针一次走一步
}
return slow; //返回中间节点的地址
}
运行结果:
9、查找单链表的倒数第k个节点,要求只能遍历一次链表
//查找单链表的倒数第k个节点,要求只能遍历一次链表
SListNode* SListFindTailKNode(SListNode *list, size_t k)
{
SListNode *fast;
SListNode *slow;
assert(list);
fast=slow=list;
while (--k) //快指针走k-1步
{
if (NULL==fast) //少于k个节点,直接返回首地址
{
return list;
}
fast=fast->_next;
}
while (fast->_next) //快慢指针循环后移
{
slow=slow->_next;
fast=fast->_next;
}
return slow;//返回倒数第k个节点的地址
}
运行结果:
10、删除链表的倒数第K个结点
void DeleteKNode(SListNode *list,size_t k)//删除链表的倒数第K个结点
{
SListNode *fast,*slow,*tmp;
assert(list);
fast=slow=list;
while (--k) //快指针走k-1步
{
if (NULL==fast) //少于k个节点,直接返回首地址
{
return;
}
fast=fast->_next;
}
while (fast->_next) //快慢指针循环后移,找到第k个节点
{
tmp=slow; //保存第k个节点的前继
slow=slow->_next;
fast=fast->_next;
}
tmp->_next=slow->_next; //链接上第k个节点后面的节点
free(slow); //释放掉第k个节点
slow=NULL;
}
运行结果:
三、整体代码和测试代码:
整体代码和测试代码在另一篇博客里(http://blog.csdn.net/qq_38646470/article/details/78976498)