两个思路:
1.将传来的链表结点一个一个反转,需要使用3个指针,分别指向前结点、当前结点、后结点。
2.从表头开始遍历,每遍历一个结点,将该结点存入一个新链表的头结点。
先说第一个,这个我做的时候有点绕,认真的把结点的指针图画出来理清楚了思路。注释把思路解释的很清楚了,代码如下:
1 #include<iostream> 2 using namespace std; 3 struct ListNode { 4 int val; 5 struct ListNode *next; 6 ListNode(){}//这样写就是加了一个默认的构造函数,无参数 7 //val(x), next(NULL) 8 9 }; 10 class Solution { 11 public: 12 ListNode* ReverseList(ListNode* pHead) { 13 if (pHead == NULL) 14 return NULL; 15 if (pHead->next == NULL) 16 return pHead; 17 18 //定义三个指针 19 ListNode*p1 = pHead; 20 ListNode*p2 = pHead; 21 ListNode*p3 = pHead; 22 23 //因为头指针要指向空,所以单独拿出来先处理 24 p1 = pHead->next; 25 p2->next = NULL; 26 while (p1!= NULL) 27 { 28 p2 = p1->next;//用来暂存指向下一个结点的指针 29 p1->next = p3; 30 //p3 = p2->next; 31 p3 = p1; //始终让p3做前结点 32 p1 = p2; //始终让p1做当前结点 33 } 34 return p3; //一直是p1做当前结点,但是后面将p3指向p1,所以应该返回p3 35 36 } 37 }; 38 int main() 39 { 40 Solution so; 41 struct ListNode list[4];//突然明白了,在这里定义的list是无参的,因此必须存在无参的构造函数,而之前我定义了一个有参的构造函数,所以系统不会给定义默认的无参构造函数 42 //要定义无参的结构体变量,必须给它加上无参的构造函数 43 list[0].val = 1; 44 list[0].next = &list[1]; 45 list[1].val = 2; 46 list[1].next = &list[2]; 47 list[2].val = 3; 48 list[2].next = &list[3]; 49 list[3].val = 4; 50 list[3].next = NULL; 51 ListNode *re = so.ReverseList(list); 52 while(re!=NULL) 53 { 54 cout << re->val << endl; 55 re= re->next; 56 } 57 return 0; 58 }
记得本科上c++课的时候,老师强调,new和delete一定要同时使用。所以在后来我用指针的时候总想着delete,包括定义指针变量也想delete。new是开辟一个空间出来,所以需要用delete释放这个空间。但是定义指针变量时,它只是一个变量,所有的变量都不需要释放,释放的是内存空间。
第二种方法,重新建立一个链表:
1 class Solution { 2 public: 3 ListNode* ReverseList(ListNode* pHead) { 4 if (pHead == NULL) 5 return NULL; 6 ListNode*p1 = NULL; 7 ListNode*p2 = NULL; 8 ListNode*p3 = NULL; 9 while (pHead != NULL)//头插法插入 10 { 11 p2 = p1; 12 p1 = pHead; 13 p3 = pHead->next; 14 p1->next = p2; 15 pHead = p3; 16 } 17 return p1; 18 19 } 20 };
这是我看答案后的版本,其实跟我的思路差不多,我的想法是吧原来的结点的第一个结点取出来然后头插插入我的新链表中。而答案的想法是直接将原来链表的第一个结点指向创建的新链表,这样可以少建立一个变量。
代码如下:
1 class Solution { 2 public: 3 ListNode* ReverseList(ListNode* pHead) { 4 if (pHead == NULL) 5 return NULL; 6 ListNode*p = pHead; 7 ListNode*Pnode = NULL;//创建新的链表结点 8 ListNode*Pnext = NULL;//用来保存原来链表的下一个结点,以防丢失 9 Pnode = p; //首先给第一个结点建立 10 Pnext = p->next; 11 Pnode->next = NULL; 12 p = Pnext; 13 while (p!= NULL) 14 { 15 Pnext = p->next; 16 p->next = Pnode; 17 Pnode = p; 18 p = Pnext; 19 } 20 return Pnode; 21 22 } 23 };
其实没必要把第一个结点单独拿出来,直接放在while里也可以,于是得到了最精简的版本:
1 class Solution { 2 public: 3 ListNode* ReverseList(ListNode* pHead) { 4 if (pHead == NULL) 5 return NULL; 6 ListNode*p = pHead; 7 ListNode*Pnode = NULL;//创建新的链表结点 8 ListNode*Pnext = NULL;//用来保存原来链表的下一个结点,以防丢失 9 while (p!= NULL)//头插法插入 10 { 11 Pnext = p->next; 12 p->next = Pnode; 13 Pnode = p; 14 p = Pnext; 15 } 16 return Pnode; 17 18 } 19 };
这个题还是有代表意义的,推荐使用第二种,更简单一些,思路也更清晰。只需要建立两个指针分别指向新的链表和原来链表的下一个结点。