第一次交换
第二次交换
第三次交换
步骤:
- 定义当前结点 current,初始值为首元结点,current = L->next;
- 定义当前结点的后继结点 pnext, pnext = current->next;
- 只要 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;
- 最后将头结点与 current 重新连上即可,L->next = current;
函数设计如下:
/* 单链表反转/逆序 */ Status ListReverse(LinkList L) { LinkList current,pnext,prev; if(L == NULL || L->next == NULL) return L; current = L->next; /* p1指向链表头节点的下一个节点 */ pnext = current->next; current->next = NULL; while(pnext) { prev = pnext->next; pnext->next = current; current = pnext; pnext = prev; printf("交换后:current = %d,next = %d ",current->data,current->next->data); } //printf("current = %d,next = %d ",current->data,current->next->data); L->next = current; /* 将链表头节点指向p1 */ return L; }
Status ListReverse2(LinkList L) { LinkList current, p; if (L == NULL) { return NULL; } current = L->next; while (current->next != NULL) { p = current->next; current->next = p->next; p->next = L->next; L->next = p; } return L; }
- p = current->next; p 就相当于前面的 pnext。(图1中a2即为p)
- current->next = p->next; p->next 就相当于 prev的角色,这句代码意思是 current 的后继指向 prev.(相当于图1中a1->next = a3(a2->next))
- p->next = L->next; 这句就是 p 的后继直接指向首元节点。(相当于图1中a2->next = a1)
- L->next = p; 然后再将头结点指向 p。(相当于图1中L->next = a2
这个是程序运行的结果。
整体创建L的元素(头插法): // 原链表,current = 68, pnext = 55,68指向18,55指向18,头结点指向55 -> 68 -> 55 -> 18 -> 45 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67 // 第一次交换后,原链表变成这样 -> 55 -> 68 -> 18 -> 45 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67 // 进行第二次交换,pnext = 18,68指向45,18变成头结点 -> 18 -> 55 -> 68 -> 45 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67 // 进行第三次交换,pnext = current->next = 45,68指向41,45变成头结点 -> 45 -> 18 -> 55 -> 68 -> 41 -> 43 -> 5 -> 28 -> 80 -> 67 // …… -> 41 -> 45 -> 18 -> 55 -> 68 -> 43 -> 5 -> 28 -> 80 -> 67 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 5 -> 28 -> 80 -> 67 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 28 -> 80 -> 67 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 80 -> 67 -> 80 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 -> 67 // current 68 没有后继,反转结束 -> 67 -> 80 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68 反转L后 -> 67 -> 80 -> 28 -> 5 -> 43 -> 41 -> 45 -> 18 -> 55 -> 68
最后附上完整代码,反转有两个函数。
- 方法1,current始终保持在第一位,pnext与prev遍历并完成交换。
- 方法2,current始终是原链表的第一个数,然后把pnext不断移动到首位。
有两个方法可以实现单链表的反转:
方法一:
#include <stdio.h> #include <stdlib.h> typedef struct Node { int data; struct Node *next; }Node; Node *head,*p; Node * ReverseLink(Node *head) { Node *p1, *p2, *p3; if(head==NULL || head->next==NULL) return head; p1=head, p2=p1->next; while(p2) { p3=p2->next; p2->next=p1; p1=p2; p2=p3; } head->next=NULL; head=p1; return head; } void CreateList(int n) { Node *q; int i; printf("Input %2d data: ",n); head=(Node *)malloc(sizeof(Node)); q=head; scanf("%d",&q->data); for(i=2;i<=n;i++) { q->next=(Node *)malloc(sizeof(Node)); q=q->next; scanf("%d",&q->data); } q->next=NULL; } void PrintList() { Node *q; q=head; while (q!=NULL) { printf("%-8d",q->data); q=q->next; } printf(" "); } void main() { CreateList(5); PrintList(); head=ReverseLink(head); PrintList(); }
方法二:
#include <iostream> #include <assert.h> using namespace std; struct LNode{ char data; LNode * next; }; LNode * initList() { LNode *head=new LNode; LNode *curPtr, *newPtr; curPtr=head; int i=0; char ch='A'; while(i++<10) { newPtr=new LNode; newPtr->data=ch++; curPtr->next=newPtr; curPtr=newPtr; } newPtr->next=NULL; return head; } void print(LNode *head) { LNode *ptr=head->next; while(ptr != NULL) { cout << ptr->data << " "; ptr=ptr->next; } cout << endl; } void reverse(LNode *head) { assert(head != NULL && head->next != NULL); LNode *ptr=head->next->next; head->next->next=NULL; while(ptr != NULL) { LNode *tmp=ptr->next; ptr->next=head->next; head->next=ptr; ptr=tmp; } } int main() { LNode *head=initList(); print(head); cout << "After reverse: " << endl; reverse(head); print(head); system("PAUSE"); return 0; }