面试题四 从尾到头打印链表
题目
输入一个链表的头结点,从尾到头反过来打印出每个结点的值。
分析
这个题目有三种解法,可以根据实际情况灵活选用。
解法一 堆栈法
设立一个堆栈,然后遍历一次链表,其间将数据依次存入堆栈。遍历完之后将所有元素依次出栈并打印即可。
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++中的容器及容器适配器都挺实用的