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


    题目

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

    分析

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

    解法一 堆栈法

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

      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++中的容器及容器适配器都挺实用的

  • 相关阅读:
    IPAD3终于发布了!苹果在5年内还是很难被超越!
    今天更新了ubuntu11.10!
    折腾两日系统重装,对比ubuntu11.04 和windows 7旗舰版!(不定时更新添加新的体验)
    DELL XPS M1530安装MAC OS X Lion 10.7.3经验分享!
    ubuntu 11.04 指纹识别的安装!
    Dlink DIR615L 和水星(mercury) MW300R桥接方法!
    POJ 3522 Slim Span(kruskal 变型)
    POJ 3621 Sightseeing Cows(SPFA + 构造负环)
    POJ 2553 The Bottom of a Graph(Tarjan)
    POJ 2728 Desert King(最优比率生成树)
  • 原文地址:https://www.cnblogs.com/scut-fm/p/3606400.html
Copyright © 2020-2023  润新知