一、题目
1、从尾到头打印单链表 (两种方法)
2、删除一个无头单链表的非尾节点(不能遍历链表)
3、在无头单链表的一个节点前插入一个节点(不能遍历链表)
4、单链表实现约瑟夫环(JosephCircle)
5、逆置/反转单链表
6、单链表排序(冒泡排序&快速排序)
7、合并两个有序链表,合并后依然有序
8、查找单链表的中间节点,要求只能遍历一次链表
9、查找单链表的倒数第k个节点,要求只能遍历一次链表
10、删除链表的倒数第K个结点
//从尾到头打印单链表
void SLinkPrintTailToHead(SLinkNode* phead)
{
if(phead==NULL)
{
return ;
}
SLinkNode* end=NULL;
SLinkNode* cur=phead;
printf(" actual:");
while( end!=phead)
{
SLinkNode* cur=phead;
//找到尾节点
while( cur->next!=end)
{
cur=cur->next;
}
printf("%c ",cur->data);
//更新尾节点
end=cur;
}
}
从尾到头打印单链表2(递归调用)
void SLinkPrintTailToHeadR(SLinkNode* phead)
{
if( phead==NULL)
{
return;
}
else
{
SLinkPrintTailToHeadR(phead->next);
printf("%c ",phead->data);
}
}
- 删除一个无头非尾节点
void SLinkDelNode(SLinkNode* pos)
{
if( pos!=NULL&&pos->next!=NULL)
{
return;
}
//保存下一个节点,便于销毁
SLinkNode* next=pos->next;
//将pos-next的值赋值给pos
pos->data=pos->next->data;
//修改pos->next指向
pos->next=pos->next->next;
//销毁next
free(next);
next=NULL;
}
- 在无头单链表的一个节点前插入一个节点
void SLinkNoHeadInsert(SLinkNode* pos,DataType value)
{
if(pos==NULL)
{
return ;
}
//创建一个新节点
SLinkNode* newnode=SLinkCreat(value);
//将pos->data和newnode的值互换
newnode->data=pos->data;
pos->data=value;
//修改pos->next和newnode->next指针指向指向
newnode->next=pos->next;
pos->next=newnode;
}
- 单链表实现约瑟夫环
SLinkNode* SLinkJoSePhCircle(SLinkNode* phead)
{
//没有环,无法构成约瑟夫环
if( phead==NULL)
{
return NULL;
}
int step=0;
SLinkNode* cur=phead;
SLinkNode* tmp=NULL;
//构造一个带环的链表
while(cur->next!=phead)
{
cur=cur->next;
}
cur->next=phead;
//开始杀人
while(cur->next!=cur)
{
cur=cur->next;
++step;
if(step==2)
{
tmp=cur->next;
cur->data=tmp->data;
cur->next=cur->next->next;
step=0;
free(tmp);
tmp=NULL;
}
}
return cur;
}
- 反转单链表
SLinkNode* SLinkReverse(SLinkNode* phead)
{
if( phead==NULL||phead->next==NULL)
{
return phead;
}
//p1,p2完成逆置,p3完成标记
SLinkNode* p1=phead;
SLinkNode* p2=p1->next;
SLinkNode* p3=p2->next;
//逆置
while(p2)
{
//将p2指向p1
p2->next=p1;
//更新p1
p1=p2;
//更新p2
p2=p3;
//更新p3
if( p3)
{
p3=p3->next;
}
}
//更改头指针指向(此时头指针还指向开始位置)
phead->next=NULL;
phead=p1;
return phead;
}
- 查找中间节点
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; //返回中间节点的地址
}
- 查找单链表的倒数第K个节点,要求只能遍历一次链表
SLinkNode* SLinkFindKNode(SLinkNode* phead,size_t k)
{
assert( phead);
//定义一个快指针,一个慢指针
SLinkNode* slow=phead;
SLinkNode* fast=phead;
//让快指针先走k-1步,然后快慢指针一起走
while(--k)
{
if( fast==NULL)
{
return phead;
}
fast=fast->next;
}
while( fast->next!=NULL)
{
slow=slow->next;
fast=fast->next;
}
//走到链表结尾,慢指针就是倒数第K个节点,返回慢指针
return slow;
}
- 单链表排序(冒泡排序)
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; //尾前移
}
}
- 合并两个有序链表
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; //返回新链表的头节点地址
}
- 求链表的长度
//求链表的长度
size_t SLinkSize(SLinkNode* phead)
{
if( phead==NULL)
{
return ;
}
SLinkNode* cur=phead;
size_t count=0;
while(cur!=NULL)
{
++count;
cur=cur->next;
}
return count;
}
//删除链表倒数第K个节点
void SLinkDelKNode(SLinkNode** pphead,size_t k)
{
//非法输入
if( pphead==NULL)
{
return ;
}
//空链表,直接返回
if( *pphead==NULL)
{
return ;
}
size_t len=SLinkSize(*pphead);
//K在链表长度之外,直接返回
if( k>len)
{
return ;
}
//K刚好等于链表的长度,直接调用头删
else if( k==len)
{
SLinkPopFront(pphead);
return ;
}
//其他位置,遍历找到第K个节点之前的节点
else
{
SLinkNode* cur=*pphead;
int i=0;
for( ;i<len-k-1;i++)
{
cur=cur->next;
}
//找到第K个节点之前的节点
SLinkNode* to_delete=cur->next;
//修改第K个节点之前的节点与第K个节点之后的节点关系指向
cur->next=to_delete->next;
//释放第K个节点,并置为NULL,避免成为野指针
free( to_delete);
to_delete=NULL;
}
}
//判断链表是否带环
//判断链表是否带环
size_t SLinkHasCircle(SLinkNode* phead)
{
if( phead==NULL)
{
return 0;
}
//定义一个快指针,一次走两步
//定义一个慢指针,一次走一步
SLinkNode* fast=phead;
SLinkNode* slow=phead;
//如果链表带环,则两个指针一定会相遇
//相遇返回1,否则返回0
while( fast!=NULL&&fast->next!=NULL)
{
fast=fast->next->next;
slow=slow->next;
if( fast==slow)
{
return 1;
}
}
return 0;
}
求环的长度
//求环的长度
size_t SLinkGetCircleLenth(SLinkNode* phead)
{
if( phead==NULL)
{
return 0;
}
//定义一个指针,指向前面快慢指针相遇点
//让其沿环走一圈,即是环长度
SLinkNode *cur=SLinkHasCircle(phead);
SLinkNode* tmp=cur;
size_t count=0;
while(cur->next!=NULL)
{
count++;
if(cur==tmp)
{
break;
}
}
return count;
}