得链表者得天下(中)

老样子,话不多说,就是锤。

设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; 


我是小纸人,谢谢大家啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值