对一个单链表进行逆序排列。

来源:互联网 发布:尚学堂 java 高淇 ppt 编辑:程序博客网 时间:2024/05/18 12:01

    算法:当建立好一个链表后,指针的方向是固定的,从某种意义上来说只能从head开始,每一个next都是指向下一个,即从左到右,如果要逆序排列,首先很容易想到要访问到尾节点,将其当做新的头结点,然后让它去指向倒数第二个倒数第三个等等。可问题来了,找到新的头结点到时很容易,那如果让它按照倒数第二个,倒数第三个......也就是从右至左的逆序访问呢?毕竟链表里没有哪个指针可以指向反方向的啊,研究了一下午的老谭的算法,终于想通了(在这里小小的膜拜下,确实牛逼!)。逆序的核心算法如下:首先去遍历初始链表,这个比较简单p2=p1;p1=p1->next;(其中p1主要访问下一结点,p2记录p1走过的地方),访问到最后我们就可以找到新的头结点(即这里的尾节点),然后赋值新的指针,newp=newhead=p1;接下来就是算法的经典步骤了,此时p1,newp,newhead都指向最后一个节点,而p2指向倒数第二个节点,立刻使p2->next=null;这样就等于丢掉了最后一个节点,使得p2指向了新的链表的尾节点(此时链表少了一个节点)。这是第一趟的步骤,为了找出规律,继续看第二趟,也就是说继续让p1,p2指向head(head是原链表的头结点,它一直都没有动,以方便每趟的初始化),然后去遍历链表节点,这时又可以找到最后一个节点(原链表的倒数第二个节点),然后又断开它,这时,已经断开了两个节点了,第一趟找到的是新的头结点,那么立刻连接这个第二次丢掉的节点,重新组建新链表,即newp->next=p1,这样这两个节点就连接起来了,可是这样还不够,为了遍历新的链表,得有一个指针啊,还得让newp指针过去,它现在还在新的头结点哪里呢(不用不是浪费了),让它去倒数第二个节点的地方(以方便以后的连接),结合起来就是newp=newp->next=p1;依次这样循环len次即可(len为链表节点数)。代码如下:

#include <stdio.h>#include <malloc.h>struct stu{int num;struct stu *next;};void main(){ int i;//用以遍历循环  int len;//链表长度  struct stu *p1,*p2,*head,*newhead,*newp;  p1=p2=head=(struct stu*)malloc(sizeof(struct stu));  printf("--------输入链表开始----------\n");  printf("输入一个节点(输入0则退出):\n");  scanf("%3d",&p1->num);  len=1;//长度加1  while(p1->num!=0)  {  p1=(struct stu*)malloc(sizeof(struct stu));//p1指向新节点  printf("继续输入节点(输入0则退出):\n");  scanf("%3d",&p1->num);  if (p1->num==0)    p2->next=NULL;//只有一个节点  else  {        p2->next=p1;    p2=p1;    len++;}  }  printf("---------输出原始链表----------\n");  p1=head;//初始化指针用以输出  for (i=1;i<=len;i++)  {  printf("%3d ",p1->num);  p1=p1->next;  }  printf("\n");  printf("------对原始链表排序并输出------\n");  for (i=1;i<=len;i++)  {    p1=p2=head;while(p1->next!=NULL)//此循环非常重要,去指向每趟尾节点{p2=p1;p1=p1->next;//此时p1指向最后一个,p2为倒数第二个,注意循环条件}if(i==1)//第一趟时,将尾节点作为新的头结点       newhead=newp=p1;elsenewp=newp->next=p1;//每趟都新加入一个之前链表丢掉的节点p2->next=NULL;//每趟的倒数第二个节的next都指向空,等于切断了倒数第一个节点  }  //输出逆序后的链表  p1=newhead;  for (i=1;i<=len;i++)  {printf("%4d",p1->num);   p1=p1->next;  }  printf("\n");}


原创粉丝点击