老样子,话不多说,就是锤。
设head指向单向非空链表,数据域值为正整数。
①求链表的中间结点。
②将两个升序链表合成一个升序链表。
③单链表的反转
④判断单链表是否有环
⑤取出有环链表中环的起始点
⑥取出有环链表中环的长度
开始锤:
1.
求链表的中间节点:
第一种方法,跑一边链表,统计一下几个节点,再跑到中间就完事。代码就不写了.
int length = 0; while(head) { head = head->next; length ++ ; }//这就是计算长度,在弄个一半就行
注意:要是奇数好办,偶数的话,要问清人家需要哪个,前半段还是后半段.
例:1 2 3 4 问人家要2 还是要4
另一个更灵巧的方法是,用两个指针,慢指针每次走一步,快指针每次走两步,当快指针走到链表的末端(NULL)时,慢指针正好指向了中间节点(大长腿跑呗)
代码如下:
ElemSN *findmidnode(ElemSN* h)
{
ElemSN* p,*q;
if(!h)//没接点返回空
return NULL;
for(q=h,p=h->next;p&&p->next;q=q->next,p=p->next->next);//查找的过程
return q;//q指向偶数的前半段
}
2.
将两个升序链表合成一个升序链表。
第一种方法,和合并升序数组一样指针上下跳就可以。
ElemSN * mergeascendlink(ElemSN *h1,ElemSN *h2)
{
if(!h1) return h2;
if(!h2) return h1;//h1空返回h2;h2空返回h1;
ElemSN *head,*p;
if(h1->data<h2->data)//确定head在哪里;
{
head=h1;
h1=h1->next;
}
else
{
head=h2;
h2=h2->next;
}
p=head;//放上P用来上下跳;
while(h1&&h2)//有一个完了就结束
{
if(h1->data>h2->data)
{
p->next=h2;//挂链
h2=h2->next;//后移
}
else
{
p->next=h1;
h1=h1->next;
}
p=p->next;//p后移
}
if(!h1) p->next=h2;//h1完了,挂上h2剩下的
else p->next=h1;//反之
return head;
}
第二种方法:
递归实现:
ElemSN * mergeascendlink(ElemSN *h1,ElemSN *h2)//这个递归呢需要大家那笔画一画在自己跑几遍就可以了。
{
if(h1==NULL) return h2;
if(h2==NULL) return h1;
ElemSN *head;
if(h1->data<h2->data)//比大小
{
h1->next = mergeascendlink(h1->next,h2);//挂链的过程,还是要自己多跑跑
head=h1;
}
else{
h2->next = mergeascendlink(h1,h2->next);
head=h2;
}
return head;
}
3.
单链表的反转,假设原链表为1->2->3,翻转以后的链表应该是1<-2<-3,即节点3变成了头节点。
看起来高大上,其实就是把链表分成第一个结点,和后面的结点,把后面的结点,头插就完事了。
代码如下:(顺便复习一下头插结点)
ElemSN * reversallink(ElemSN * h)
{
if(!h)
return NULL;//空链表返回NULL
ElemSN * p,*q;
p=h->next;
h->next=NULL;//断开
while(p)//头插
{
q=p;
p=p->next;
q->next=h;
h=q;
}
return h;
}
思考题:以组为单位翻转链表,组的长度用K表示,比如原链表为1->2->3->4->5,当K=2时,翻转的结果为2->1->4->3->5,当K=3时,翻转的结果为3->2->1->4->5,即先翻转K个,再翻转K个,当剩下的节点数小于K时,就不用翻转了。
可以试着做一下,下次有可能就给大家分享出来了。(关键有点长。。。)
4.
判断是否有环。做法也是用快慢指针,如果没有环,快指针一定先到达链表的末端(NULL),如果有环,快、慢指针一定会相遇在环中。(那么就是单循环双出口,出口一没环,出口二有环)
代码如下:
int judgering(ElemSN * h)
{
ElemSN * p,*q;
int flag=0;//先假设没有环
p=q=h;
while(q&&q->next)//从循环条件出来,一定没环(因为到了NULL)
{
p=p->next;
q=q->next->next;
if(p==q)
{
flag=1;
break;//break出来;有环,改一下flag的值
}
}
return flag;//flag=0没环;=1有环,主调判断下就完事了
}
5.
⑤取出有环链表中环的起始点
使用前后指针,(你先走,我再走)不是快慢指针,不是快慢指针,不是快慢指针,两个指针相遇的地方就是环的起始点。
代码如下:
ElemSN * detectEntry(ElemSN * head)
{
ElemSN *first,second;
//使用前后指针,此时fast每次也只移动一步
ElemSN *first = head , *second = head;
while(circleLen--) first = first->next; // first指针先出发
//然后两个指针同时向前走,每次走一步
while(first!=second){ first = first->next; second = second->next ; }
return first;
}
6.
⑥取出有环链表中环的长度
首先要找到环的起始点。指上一个指针,架设循环,弄一个累加器,没到起始点就加一;
代码如下:
int cnt = 1;ElemSN *temp = first->next;
while(temp!=first) { temp = temp->next; cnt ++; }
这里偷个懒,直接用了上面的first;就是简单的累加啦。大家不要在意。
最后附上总的代码:(我这里没环所以关于环的那几个,大家自己下去敲一下哦)
#include<stdio.h>
#include<stdlib.h>
#define N 6
typedef struct node{
int data;
struct node *next;
}ElemSN;
ElemSN *createlink1(int a[])
{
ElemSN *h=NULL,*tail,*p;
for(int i=0;i<N;i++)
{
p=(ElemSN*)malloc(sizeof(ElemSN));//分配一个动态单元给p
p->data=a[i];//数据域赋值
p->next=NULL;//指针域赋空
if(!h)
h=tail=p;//判断是不是第一个结点,是,头尾都指上来
else
tail=tail->next=p; //不是,挂链,挪尾指针。
}
return h;//返回头指针h
}
ElemSN *findmidnode(ElemSN* h)
{
ElemSN* p,*q;
if(!h)//没接点返回空
return NULL;
for(q=h,p=h->next;p&&p->next;q=q->next,p=p->next->next);//查找的过程
return q;//q指向偶数的前半段
}
ElemSN * mergeascendlink(ElemSN *h1,ElemSN *h2)//这个递归呢需要大家那笔画一画在自己跑几遍就可以了。
{
if(h1==NULL) return h2;
if(h2==NULL) return h1;
ElemSN *head;
if(h1->data<h2->data)//比大小
{
h1->next = mergeascendlink(h1->next,h2);//挂链的过程,还是要自己多跑跑
head=h1;
}
else{
h2->next = mergeascendlink(h1,h2->next);
head=h2;
}
return head;
}
/*ElemSN * mergeascendlink(ElemSN *h1,ElemSN *h2)//合并升序链(非递归)
{
if(!h1) return h2;
if(!h2) return h1;//h1空返回h2;h2空返回h1;
ElemSN *head,*p;
if(h1->data<h2->data)//确定head在哪里;
{
head=h1;
h1=h1->next;
}
else
{
head=h2;
h2=h2->next;
}
p=head;//放上P用来上下跳;
while(h1&&h2)//有一个完了就结束
{
if(h1->data>h2->data)
{
p->next=h2;//挂链
h2=h2->next;//后移
}
else
{
p->next=h1;
h1=h1->next;
}
p=p->next;//p后移
}
if(!h1) p->next=h2;//h1完了,挂上h2剩下的
else p->next=h1;//反之
return head;
}*/
ElemSN * reversallink(ElemSN * h)
{
if(!h)
return NULL;//空链表返回NULL
ElemSN * p,*q;
p=h->next;
h->next=NULL;//断开
while(p)//头插
{
q=p;
p=p->next;
q->next=h;
h=q;
}
return h;
}
void printlink(ElemSN*h)
{
ElemSN*p;
for(p=h;p;p=p->next)
printf("%5d",p->data);
printf("\n");
}
int main (void)
{
int a[N]={1,2,3,4,5,6};
ElemSN *head1=NULL,*head2=NULL,*head=NULL,*p,*q;
//正向创建链表
head1=createlink1(a);//用head1接收头指针
head2=createlink1(a);
//输出链表
printlink(head1);
p=findmidnode(head1);
printf("中间结点的值是:%d\n",p->data);
head=mergeascendlink(head1,head2);//合并
printlink(head);//输出一下合并后的
printf("\n");
q=reversallink(head); //反转链表
printlink(q);//输出反转后的
return 0;
}
我是小纸人,谢谢大家啦。