面试题四 从尾到头打印链表

题目

  输入一个链表的头结点,从尾到头反过来打印出每个结点的值。

分析

  这个题目有三种解法,可以根据实际情况灵活选用。

解法一 堆栈法

  设立一个堆栈,然后遍历一次链表,其间将数据依次存入堆栈。遍历完之后将所有元素依次出栈并打印即可。

  PS:这里堆栈直接用C++中的stack容器适配器实现

代码实现( 含测试 )

 1 #include <iostream>
 2 #include <stack>
 3 
 4 using namespace std;
 5 
 6 /*
 7  * 定义结点类型
 8 */
 9 struct ListNode {
10     int value;
11     ListNode *next;
12 };
13 
14 // 逆序打印函数
15 void rPrint(ListNode * head);
16 
17 /*
18  * 测试函数:建立一个链表,有10个结点,结点的值依次为1-10。
19  *          然后调用rPrint函数将数据从尾到头打印出来。
20 */
21 int main()
22 {
23     ListNode *head = new ListNode();
24     head->value = 1;
25 
26     ListNode *q = head;
27     ListNode *p = NULL;
28 
29     for (int i=2; i<=10; i++) {
30         p = new ListNode();
31         p->value = i;
32         q->next = p;
33         q = q->next;
34     }
35     p->next = NULL;
36 
37     p = head;
38     cout << "目标链表:" << endl;
39     while (p != NULL) {
40         cout << p->value << " ";
41         p = p->next;
42     }
43     cout << endl;
44 
45     rPrint(head);
46 
47     return 0;
48 }
49 
50 /*
51  * 逆序打印函数
52 */
53 void rPrint(ListNode * head)
54 {
55     // 定义一个堆栈( 容器适配器 )
56     stack<ListNode *> s;
57 
58     // 顺序遍历链表并将数据存进堆栈
59     ListNode *p = head;
60     while (p!=NULL) {
61         s.push(p);
62         p = p->next;
63     }
64 
65     // 所有数据出栈并打印
66     cout << "逆序打印之:" << endl;
67     while (!s.empty()) {
68         p = s.top();
69         s.pop();
70         cout << p->value << " ";
71     }
72     
73     cout << endl;
74 }

运行测试

  

解法二 递归法

  递归打印此链表,这也是最简单的解法。

代码实现( 含测试 )

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 /*
 6  * 定义结点类型
 7 */
 8 struct ListNode {
 9     int value;
10     ListNode *next;
11 };
12 
13 // 逆序打印函数
14 void rPrint(ListNode * head);
15 
16 /*
17  * 测试函数:建立一个链表,有10个结点,结点的值依次为1-10。
18  *          然后调用rPrint函数将数据从尾到头打印出来。
19 */
20 int main()
21 {
22     ListNode *head = new ListNode();
23     head->value = 1;
24 
25     ListNode *q = head;
26     ListNode *p = NULL;
27 
28     for (int i=2; i<=10; i++) {
29         p = new ListNode();
30         p->value = i;
31         q->next = p;
32         q = q->next;
33     }
34     p->next = NULL;
35 
36     p = head;
37     cout << "目标链表:" << endl;
38     while (p != NULL) {
39         cout << p->value << " ";
40         p = p->next;
41     }
42     cout << endl;
43 
44     rPrint(head);
45 
46     cout << endl;
47 
48     return 0;
49 }
50 
51 /*
52  * 逆序打印函数
53 */
54 void rPrint(ListNode * head)
55 {
56     if (head == NULL)
57         return;
58     
59     if (head->next != NULL) {
60         rPrint(head->next);
61         cout << head->value << " ";
62     }
63     else
64         cout << head->value << " "; // 递归“出口”
65 }

运行测试

  

解法三 临时修改链表法

  如果有些时候要求你不能使用栈或者递归( 内存空间很小 ),这时候应当使用这种方法:

  1. 首先将链表从头到尾翻转一次,同时遍历指针到达表尾。

  2. 然后将链表从尾到头翻转一次,在这次的翻转过程中同时输出结点数据。

代码实现( 含测试 )

  1 #include <iostream>
  2 
  3 using namespace std;
  4 
  5 /*
  6  * 定义结点类型
  7 */
  8 struct ListNode {
  9     int value;
 10     ListNode *next;
 11 };
 12 
 13 // 逆序打印函数
 14 void rPrint(ListNode * head);
 15 
 16 /*
 17  * 测试函数:建立一个链表,有10个结点,结点的值依次为1-10。
 18  *          然后调用rPrint函数将数据从尾到头打印出来。
 19 */
 20 int main()
 21 {
 22     ListNode *head = new ListNode();
 23     head->value = 1;
 24 
 25     ListNode *q = head;
 26     ListNode *p = NULL;
 27 
 28     for (int i=2; i<=10; i++) {
 29         p = new ListNode();
 30         p->value = i;
 31         q->next = p;
 32         q = q->next;
 33     }
 34     p->next = NULL;
 35 
 36     p = head;
 37     cout << "目标链表:" << endl;
 38     while (p != NULL) {
 39         cout << p->value << " ";
 40         p = p->next;
 41     }
 42     cout << endl;
 43 
 44     rPrint(head);
 45 
 46     return 0;
 47 }
 48 
 49 /*
 50  * 逆序打印函数
 51 */
 52 void rPrint(ListNode * head)
 53 {
 54     /*
 55      * 下面三个if判断分别处理结点数为0,1,2时候的情况。
 56     */
 57     if (head == NULL)
 58         return;
 59     if (head != NULL && head->next == NULL) {
 60         cout << head->value << endl;
 61         return;
 62     }
 63     if (head != NULL && head->next != NULL && head->next->next == NULL) {
 64         cout << head->next->value << " " << head->value << endl;
 65         return;
 66     }
 67 
 68     // 下面是结点数大于等于3时候的处理。
 69 
 70     // 首先,翻转链表一次。
 71     ListNode *s, *p, *q;
 72     q = head; p = head->next; s = head->next->next;
 73     q->next = NULL; // 这步别忘
 74 
 75     while (s != NULL) {
 76         p->next = q;
 77         q = p;
 78         p = s;
 79         s = s->next;
 80     }
 81     // 收尾
 82     p->next = q;
 83 
 84     // 然后,再翻转链表一次。
 85     q = p;
 86     p = q->next;
 87     s = p->next;
 88 
 89     q->next = NULL; // 这步别忘
 90     cout << q->value << " " << p->value << " "; // 先将头两个结点的数据输出
 91     while (s != NULL) {
 92         cout << s->value << " "; // 翻转的过程中输出链表数据
 93         p->next = q;
 94         q = p;
 95         p = s;
 96         s = s->next;
 97     }
 98     // 再次收尾
 99     p->next = q;
100 
101     cout << endl;
102 }

运行测试

  

小结

  C++中的容器及容器适配器都挺实用的

 

posted on 2014-03-17 22:55  空山悟  阅读(196)  评论(0编辑  收藏  举报

导航