zoukankan      html  css  js  c++  java
  • 单链表反转的分析及实现

    • 我先画一个单链表,这个单链表有4个元素。我的思路就是,每次把第二个元素提到最前面来。比如下面是第一次交换,我们先让头结点的next域指向结点a2,再让结点a1的next域指向结点a3,最后将结点a2的next域指向结点a1,就完成了第一次交换。
    第一次交换
    • 然后进行相同的交换将结点a3移动到结点a2的前面,然后再将结点a4移动到结点a3的前面就完成了反转。
    第二次交换
    第三次交换
    • 思路有了,那就可以写代码了。这里我们需要额外的两个工作指针来辅助交换。这个下面的步骤慢慢理解下,结合图片。注意结点之间的关系要先断再连。

    步骤:

    1. 定义当前结点 current,初始值为首元结点,current = L->next;
    2. 定义当前结点的后继结点 pnext, pnext = current->next; 
    3. 只要 pnext 存在,就执行以下循环:
      • 定义新节点 prev,它是 pnext的后继结点,prev = pnext->next;
      • 把pnext的后继指向current, pnext->next = current;
      • 此时,pnext 实际上已经到了 current 前一位成为新的current,所以这个时候 current 结点实际上成为新的 pnext,current = pnext;
      • 此时,新的 current 就是 pnext,current = pnext;
      • 而新的 pnext 就是 prev,pnext = prev;
    4. 最后将头结点与 current 重新连上即可,L->next = current;

    函数设计如下:

    01 /* 单链表反转/逆序 */
    02 Status ListReverse(LinkList L)
    03 {
    04     LinkList current,pnext,prev;
    05     if(L == NULL || L->next == NULL)
    06         return L;
    07     current = L->next;  /* p1指向链表头节点的下一个节点 */
    08     pnext = current->next;
    09     current->next = NULL;
    10     while(pnext)
    11     {
    12         prev = pnext->next;
    13         pnext->next = current;
    14         current = pnext;
    15         pnext = prev;
    16         printf("交换后:current = %d,next = %d ",current->data,current->next->data);
    17     }
    18     //printf("current = %d,next = %d ",current->data,current->next->data);
    19     L->next = current;  /* 将链表头节点指向p1 */
    20     return L;
    21 }
    • 其实在你写函数的时候,我也写了个函数,也能运行。思路也差不多,不过你的current一直是表的第一个结点,我这里的current始终是首元结点的值,我的函数需要每次对pnext重新赋值。一会解释下。
    01 Status ListReverse2(LinkList L)
    02 {
    03     LinkList current, p;
    04  
    05     if (L == NULL)
    06     {
    07         return NULL;
    08     }
    09     current = L->next;
    10     while (current->next != NULL)
    11     {
    12         p = current->next;
    13         current->next = p->next;
    14         p->next = L->next;
    15         L->next = p;
    16     }
    17     return L;
    18 }
    1. p = current->next; p 就相当于前面的 pnext。(图1中a2即为p)
    2. current->next = p->next; p->next 就相当于 prev的角色,这句代码意思是 current 的后继指向 prev.(相当于图1中a1->next = a3(a2->next))
    3. p->next = L->next; 这句就是 p 的后继直接指向首元节点。(相当于图1中a2->next = a1)
    4. L->next = p; 然后再将头结点指向 p。(相当于图1中L->next = a2)
    • 参照图就很容易理解上面的步骤了。我觉得我这么写比你的清晰一些。我先将current指向prev,再将pnext指向current,最后将头结点指向pnext。

    这个是程序运行的结果。

    01 整体创建L的元素(头插法):
    02 // 原链表,current = 68, pnext = 55,68指向18,55指向18,头结点指向55
    03 -> 68 -> 55 -> 18 -> 45 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67
    04  
    05 // 第一次交换后,原链表变成这样
    06 -> 55 -> 68 -> 18 -> 45 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67
    07 // 进行第二次交换,pnext = 18,68指向45,18变成头结点
    08 -> 18 -> 55 -> 68 -> 45 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67
    09 // 进行第三次交换,pnext = current->next = 45,68指向41,45变成头结点
    10 -> 45 -> 18 -> 55 -> 68 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67
    11 // ……
    12 -> 41 -> 45 -> 18 -> 55 -> 68 -> 43 -> 5 -> 28 -> 80 -> 67
    13  
    14 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 5 -> 28 -> 80 -> 67
    15  
    16 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 28 -> 80 -> 67
    17  
    18 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 80 -> 67
    19  
    20 -> 80 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 67
    21 // current 68 没有后继,反转结束
    22 -> 67 -> 80 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68
    23  
    24  
    25 反转L后
    26 -> 67 -> 80 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68

    最后附上完整代码,反转有两个函数。

    • 方法1,current始终保持在第一位,pnext与prev遍历并完成交换。
    • 方法2,current始终是原链表的第一个数,然后把pnext不断移动到首位。
      1 #include<stdio.h>
      2 #include<stdlib.h>
      3 #include<time.h>
      4 
      5 #define OK 1
      6 #define ERROR 0
      7 #define TRUE 1
      8 #define FALSE 0
      9 
     10 #define MAXSIZE 20 /* 存储空间初始分配量 */
     11 
     12 typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
     13 typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */
     14 
     15 typedef struct Node
     16 {
     17     ElemType data;
     18     struct Node *next;
     19 }Node;
     20 /* 定义LinkList */
     21 typedef struct Node *LinkList;
     22 
     23 /* 初始化顺序线性表 */
     24 Status InitList(LinkList *L)
     25 {
     26     *L=(LinkList)malloc(sizeof(Node)); /* 产生头结点,并使L指向此头结点 */
     27     if(!(*L)) /* 存储分配失败 */
     28     {
     29         return ERROR;
     30     }
     31     (*L)->next=NULL; /* 指针域为空 */
     32 
     33     return OK;
     34 }
     35 
     36 /* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */
     37 int ListLength(LinkList L)
     38 {
     39     int i=0;
     40     LinkList p=L->next; /* p指向第一个结点 */
     41     while(p)
     42     {
     43         i++;
     44         p=p->next;
     45     }
     46     return i;
     47 }
     48 
     49 /* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */
     50 Status ClearList(LinkList *L)
     51 {
     52     LinkList p,q;
     53     p=(*L)->next;           /*  p指向第一个结点 */
     54     while(p)                /*  没到表尾 */
     55     {
     56         q=p->next;
     57         free(p);
     58         p=q;
     59     }
     60     (*L)->next=NULL;        /* 头结点指针域为空 */
     61     return OK;
     62 }
     63 
     64 /* 初始条件:顺序线性表L已存在 */
     65 /* 操作结果:依次对L的每个数据元素输出 */
     66 Status ListTraverse(LinkList L)
     67 {
     68     LinkList p=L->next;
     69     while(p)
     70     {
     71         visit(p->data);
     72         p=p->next;
     73     }
     74     printf("
    ");
     75     return OK;
     76 }
     77 
     78 Status visit(ElemType c)
     79 {
     80     printf("-> %d ",c);
     81     return OK;
     82 }
     83 
     84 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
     85 /* 操作结果:用e返回L中第i个数据元素的值 */
     86 Status GetElem(LinkList L,int i,ElemType *e)
     87 {
     88     int j;
     89     LinkList p;        /* 声明一结点p */
     90     p = L->next;        /* 让p指向链表L的第一个结点 */
     91     j = 1;        /*  j为计数器 */
     92     while (p && j < i)  /* p不为空或者计数器j还没有等于i时,循环继续 */
     93     {
     94         p = p->next;  /* 让p指向下一个结点 */
     95         ++j;
     96     }
     97     if ( !p || j>i )
     98         return ERROR;  /*  第i个元素不存在 */
     99     *e = p->data;   /*  取第i个元素的数据 */
    100     return OK;
    101 }
    102 
    103 /* 初始条件:顺序线性表L已存在 */
    104 /* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
    105 /* 若这样的数据元素不存在,则返回值为0 */
    106 int LocateElem(LinkList L,ElemType e)
    107 {
    108     int i=0;
    109     LinkList p=L->next;
    110     while(p)
    111     {
    112         i++;
    113         if(p->data==e) /* 找到这样的数据元素 */
    114                 return i;
    115         p=p->next;
    116     }
    117 
    118     return 0;
    119 }
    120 
    121 /*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
    122 void CreateListHead(LinkList *L, int n)
    123 {
    124     LinkList p;
    125     int i;
    126     srand(time(0));                         /* 初始化随机数种子 */
    127     *L = (LinkList)malloc(sizeof(Node));
    128     (*L)->next = NULL;                      /*  先建立一个带头结点的单链表 */
    129     for (i=0; i < n; i++)
    130     {
    131         p = (LinkList)malloc(sizeof(Node)); /*  生成新结点 */
    132         p->data = rand()%100+1;             /*  随机生成100以内的数字 */
    133         p->next = (*L)->next;
    134         (*L)->next = p;                        /*  插入到表头 */
    135     }
    136 }
    137 
    138 /*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
    139 void CreateListTail(LinkList *L, int n)
    140 {
    141     LinkList p,r;
    142     int i;
    143     srand(time(0));                      /* 初始化随机数种子 */
    144     *L = (LinkList)malloc(sizeof(Node)); /* L为整个线性表 */
    145     r=*L;                                /* r为指向尾部的结点 */
    146     for (i=0; i < n; i++)
    147     {
    148         p = (Node *)malloc(sizeof(Node)); /*  生成新结点 */
    149         p->data = rand()%100+1;           /*  随机生成100以内的数字 */
    150         r->next=p;                        /* 将表尾终端结点的指针指向新结点 */
    151         r = p;                            /* 将当前的新结点定义为表尾终端结点 */
    152     }
    153     r->next = NULL;                       /* 表示当前链表结束 */
    154 }
    155 
    156 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L), */
    157 /* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
    158 Status ListInsert(LinkList *L,int i,ElemType e)
    159 {
    160     int j;
    161     LinkList p,s;
    162     p = *L;     /* 声明一个结点 p,指向头结点 */
    163     j = 1;
    164     while (p && j < i)     /* 寻找第i个结点 */
    165     {
    166         p = p->next;
    167         ++j;
    168     }
    169     if (!p || j > i)
    170         return ERROR;   /* 第i个元素不存在 */
    171     s = (LinkList)malloc(sizeof(Node));  /*  生成新结点(C语言标准函数) */
    172     s->data = e;
    173     s->next = p->next;      /* 将p的后继结点赋值给s的后继  */
    174     p->next = s;          /* 将s赋值给p的后继 */
    175     return OK;
    176 }
    177 
    178 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
    179 /* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
    180 Status ListDelete(LinkList *L,int i,ElemType *e)
    181 {
    182     int j;
    183     LinkList p,q;
    184     p = *L;
    185     j = 1;
    186     while (p->next && j < i)    /* 遍历寻找第i个元素 */
    187     {
    188         p = p->next;
    189         ++j;
    190     }
    191     if (!(p->next) || j > i)
    192         return ERROR;           /* 第i个元素不存在 */
    193     q = p->next;
    194     p->next = q->next;            /* 将q的后继赋值给p的后继 */
    195     *e = q->data;               /* 将q结点中的数据给e */
    196     free(q);                    /* 让系统回收此结点,释放内存 */
    197     return OK;
    198 }
    199 
    200 /* 单链表反转/逆序 */
    201 Status ListReverse(LinkList L)
    202 {
    203     LinkList current,pnext,prev;
    204     if(L == NULL || L->next == NULL)
    205         return L;
    206     current = L->next;  /* p1指向链表头节点的下一个节点 */
    207     pnext = current->next;
    208     current->next = NULL;
    209     while(pnext)
    210     {
    211         prev = pnext->next;
    212         pnext->next = current;
    213         current = pnext;
    214         pnext = prev;
    215     }
    216     //printf("current = %d,next = %d 
    ",current->data,current->next->data);
    217     L->next = current;  /* 将链表头节点指向p1 */
    218     return L;
    219 }
    220 
    221 Status ListReverse2(LinkList L)
    222 {
    223     LinkList current, p;
    224 
    225     if (L == NULL)
    226     {
    227         return NULL;
    228     }
    229     current = L->next;
    230     while (current->next != NULL)
    231     {
    232         p = current->next;
    233         current->next = p->next;
    234         p->next = L->next;
    235         L->next = p;
    236         ListTraverse(L);
    237         printf("current = %d, 
    ", current -> data);
    238     }
    239     return L;
    240 }
    241 
    242 int main()
    243 {
    244     LinkList L;
    245     Status i;
    246     int j,k,pos,value;
    247     char opp;
    248     ElemType e;
    249 
    250     i=InitList(&L);
    251     printf("链表L初始化完毕,ListLength(L)=%d
    ",ListLength(L));
    252 
    253     printf("
    1.整表创建(头插法) 
    2.整表创建(尾插法) 
    3.遍历操作 
    4.插入操作");
    254     printf("
    5.删除操作 
    6.获取结点数据 
    7.查找某个数是否在链表中 
    8.置空链表");
    255     printf("
    9.链表反转逆序");
    256     printf("
    0.退出 
    请选择你的操作:
    ");
    257     while(opp != '0'){
    258         scanf("%c",&opp);
    259         switch(opp){
    260             case '1':
    261                 CreateListHead(&L,10);
    262                 printf("整体创建L的元素(头插法):
    ");
    263                 ListTraverse(L);
    264                 printf("
    ");
    265                 break;
    266 
    267             case '2':
    268                 CreateListTail(&L,10);
    269                 printf("整体创建L的元素(尾插法):
    ");
    270                 ListTraverse(L);
    271                 printf("
    ");
    272                 break;
    273 
    274             case '3':
    275                 ListTraverse(L);
    276                 printf("
    ");
    277                 break;
    278 
    279             case '4':
    280                 printf("要在第几个位置插入元素?");
    281                 scanf("%d",&pos);
    282                 printf("插入的元素值是多少?");
    283                 scanf("%d",&value);
    284                 ListInsert(&L,pos,value);
    285                 ListTraverse(L);
    286                 printf("
    ");
    287                 break;
    288 
    289             case '5':
    290                 printf("要删除第几个元素?");
    291                 scanf("%d",&pos);
    292                 ListDelete(&L,pos,&e);
    293                 printf("删除第%d个元素成功,现在链表为:
    ", pos);
    294                 ListTraverse(L);
    295                 printf("
    ");
    296                 break;
    297 
    298             case '6':
    299                 printf("你需要获取第几个元素?");
    300                 scanf("%d",&pos);
    301                 GetElem(L,pos,&e);
    302                 printf("第%d个元素的值为:%d
    ", pos, e);
    303                 printf("
    ");
    304                 break;
    305 
    306             case '7':
    307                 printf("输入你需要查找的数:");
    308                 scanf("%d",&pos);
    309                 k=LocateElem(L,pos);
    310                 if(k)
    311                     printf("第%d个元素的值为%d
    ",k,pos);
    312                 else
    313                     printf("没有值为%d的元素
    ",pos);
    314                 printf("
    ");
    315                 break;
    316 
    317             case '8':
    318                 i=ClearList(&L);
    319                 printf("
    清空L后:ListLength(L)=%d
    ",ListLength(L));
    320                 ListTraverse(L);
    321                 printf("
    ");
    322                 break;
    323 
    324             case '9':
    325                 ListReverse2(L);
    326                 printf("
    反转L后
    ");
    327                 ListTraverse(L);
    328                 printf("
    ");
    329                 break;
    330 
    331             case '0':
    332                 exit(0);
    333         }
    334     }
    335     return 0;
    336 }
    View Code

    有两个方法可以实现单链表的反转:

    方法一:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 typedef struct Node
     5 {
     6     int data;
     7     struct Node *next; 
     8 }Node; 
     9 Node *head,*p; 
    10 
    11 Node * ReverseLink(Node *head)
    12 {
    13     Node *p1, *p2, *p3;
    14     if(head==NULL || head->next==NULL)
    15         return head;
    16     p1=head, p2=p1->next;
    17     while(p2)
    18     {
    19         p3=p2->next;
    20         p2->next=p1;
    21         p1=p2;
    22         p2=p3;
    23     }
    24     head->next=NULL;
    25     head=p1;
    26     return head;
    27 }
    28 
    29 void CreateList(int n)
    30 {
    31     Node *q;  
    32     int i;
    33     printf("Input %2d data: ",n); 
    34     head=(Node *)malloc(sizeof(Node)); 
    35     q=head;
    36     scanf("%d",&q->data);
    37     for(i=2;i<=n;i++)
    38     {
    39         q->next=(Node *)malloc(sizeof(Node));
    40         q=q->next;
    41         scanf("%d",&q->data);
    42     }
    43     q->next=NULL;
    44 } 
    45 
    46 void PrintList() 
    47 { 
    48     Node *q; 
    49     q=head; 
    50     while (q!=NULL) 
    51     { 
    52         printf("%-8d",q->data);
    53         q=q->next;
    54     }
    55     printf("
    ");
    56 }
    57 
    58 void main()
    59 {
    60     CreateList(5);
    61     PrintList();
    62     head=ReverseLink(head);
    63     PrintList();
    64 }

    方法二:

     1 #include <iostream>
     2 #include <assert.h>
     3 using namespace std; 
     4 
     5 struct LNode{    
     6     char data;   
     7     LNode * next;
     8 }; 
     9 
    10 LNode * initList()
    11 {   
    12     LNode *head=new LNode; 
    13     LNode *curPtr, *newPtr;  
    14     curPtr=head;   
    15     int i=0;    
    16     char ch='A';   
    17     while(i++<10) 
    18     {        
    19         newPtr=new LNode; 
    20         newPtr->data=ch++; 
    21         curPtr->next=newPtr;
    22         curPtr=newPtr;
    23     }    
    24     newPtr->next=NULL;
    25     return head;
    26 } 
    27 
    28 void print(LNode *head)
    29 {    
    30     LNode *ptr=head->next;
    31     while(ptr != NULL)
    32     {        
    33         cout << ptr->data << "  ";
    34         ptr=ptr->next;
    35     }    
    36     cout << endl;
    37 }  
    38 
    39 void reverse(LNode *head)
    40 {   
    41     assert(head != NULL && head->next != NULL);
    42     LNode *ptr=head->next->next;
    43     head->next->next=NULL;     
    44     while(ptr != NULL)   
    45     {       
    46         LNode *tmp=ptr->next;    
    47         ptr->next=head->next;   
    48         head->next=ptr;        
    49         ptr=tmp;
    50     }
    51 } 
    52 
    53 int main()
    54 {   
    55     LNode *head=initList();  
    56     print(head);   
    57     cout << "After reverse: " << endl; 
    58     reverse(head);   
    59     print(head);     
    60     system("PAUSE");   
    61     return 0;
    62 }

    参考:http://www.cnblogs.com/heyonggang/p/3304838.html

            http://www.nowamagic.net/librarys/veda/detail/2241

             http://blog.csdn.net/hyg0811/article/details/11113623

  • 相关阅读:
    [例程]string.trim().length()的用法
    用各种look and feel打造swing界面
    深入浅出Java多线程(1)方法 join
    eclipse中cvs使用配置
    什么时候用Vector, 什么时候改用ArrayList?
    array,vertor,arraylist,hashable,hashmap等几个易混淆概念的区别
    java.lang.Class.getResource()这哥个方法主要是做什么用
    织梦dedecms实现按照字母搜索的实现方法
    浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值
    用java –jar 命令运行Jar包
  • 原文地址:https://www.cnblogs.com/heyonggang/p/3304838.html
Copyright © 2011-2022 走看看