单链表反转的分析及实现

  • 我先画一个单链表,这个单链表有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 \n",current->data,current->next->data);
17     }
18     //printf("current = %d,next = %d \n",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("\n");

 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 \n",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, \n", 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\n",ListLength(L));

252 

253     printf("\n1.整表创建(头插法) \n2.整表创建(尾插法) \n3.遍历操作 \n4.插入操作");

254     printf("\n5.删除操作 \n6.获取结点数据 \n7.查找某个数是否在链表中 \n8.置空链表");

255     printf("\n9.链表反转逆序");

256     printf("\n0.退出 \n请选择你的操作:\n");

257     while(opp != '0'){

258         scanf("%c",&opp);

259         switch(opp){

260             case '1':

261                 CreateListHead(&L,10);

262                 printf("整体创建L的元素(头插法):\n");

263                 ListTraverse(L);

264                 printf("\n");

265                 break;

266 

267             case '2':

268                 CreateListTail(&L,10);

269                 printf("整体创建L的元素(尾插法):\n");

270                 ListTraverse(L);

271                 printf("\n");

272                 break;

273 

274             case '3':

275                 ListTraverse(L);

276                 printf("\n");

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("\n");

287                 break;

288 

289             case '5':

290                 printf("要删除第几个元素?");

291                 scanf("%d",&pos);

292                 ListDelete(&L,pos,&e);

293                 printf("删除第%d个元素成功,现在链表为:\n", pos);

294                 ListTraverse(L);

295                 printf("\n");

296                 break;

297 

298             case '6':

299                 printf("你需要获取第几个元素?");

300                 scanf("%d",&pos);

301                 GetElem(L,pos,&e);

302                 printf("第%d个元素的值为:%d\n", pos, e);

303                 printf("\n");

304                 break;

305 

306             case '7':

307                 printf("输入你需要查找的数:");

308                 scanf("%d",&pos);

309                 k=LocateElem(L,pos);

310                 if(k)

311                     printf("第%d个元素的值为%d\n",k,pos);

312                 else

313                     printf("没有值为%d的元素\n",pos);

314                 printf("\n");

315                 break;

316 

317             case '8':

318                 i=ClearList(&L);

319                 printf("\n清空L后:ListLength(L)=%d\n",ListLength(L));

320                 ListTraverse(L);

321                 printf("\n");

322                 break;

323 

324             case '9':

325                 ListReverse2(L);

326                 printf("\n反转L后\n");

327                 ListTraverse(L);

328                 printf("\n");

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("\n");

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

 

你可能感兴趣的:(单链表)