面试题5:从尾到头打印链表
2018-01-25 20:39
309 查看
题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。
链表结点定义如下:
看到这道题后,很多人的第一反应是从头到尾输出将会比较简单,于是我们很自然的想到把链表中链接结点的指针反转过来,改变链表的方向,然后就可以从头到尾输出了。但该方法会改变原来链表的结构。是否允许在打印链表的时候修改链表的结构?这个取决于面试官的需求,因此在面试的时候我们要询问清楚面试官的要求。
通常打印是一个只读操作,我们不希望打印时修改内容。假设面试官也要求这个题目不能改变链表的结构。
接下来我们想到解决这个问题肯定要遍历链表。遍历的顺序是从头到尾的顺序,可输出的顺序却是从尾到头,也就是说第一个遍历到的结点最后一个输出,而最后一个遍历到的结点第一个输出。这就是典型的“后进先出”,我们可以用栈实现这种顺序。每经过一个结点的时候,把该结点放到一个栈中,当遍历完整个链表后,再从栈顶开始逐个输出结点的值,此时输出的结点的顺序已经反转过来了。这种思路的实现代码如下:
既然想到了用栈来实现这个函数,而递归在本质上就是一个栈结构,于是很自然的又想到了用递归来实现。要实现反过来输出链表,我们每访问到一个结点的时候,先递归输出它后面的结点,再输出该结点自身,这样链表的输出结果就反过来了。
基于这样的思路,不难写出如下代码:
上面的基于递归的代码看起来很简洁,但有个问题:当链表非常长的时候,就会导致函数调用的层级很深,从而有可能导致函数调用栈溢出。显示用栈基于循环实现的代码的鲁棒性要好一些。
附上自己的代码:
(1) 头结点中的数据域不存放数据的
(2)头结点中的数据域存放数据的
链表结点定义如下:
struct ListNode { int m_nKey; ListNode* m_pNext; };
看到这道题后,很多人的第一反应是从头到尾输出将会比较简单,于是我们很自然的想到把链表中链接结点的指针反转过来,改变链表的方向,然后就可以从头到尾输出了。但该方法会改变原来链表的结构。是否允许在打印链表的时候修改链表的结构?这个取决于面试官的需求,因此在面试的时候我们要询问清楚面试官的要求。
通常打印是一个只读操作,我们不希望打印时修改内容。假设面试官也要求这个题目不能改变链表的结构。
接下来我们想到解决这个问题肯定要遍历链表。遍历的顺序是从头到尾的顺序,可输出的顺序却是从尾到头,也就是说第一个遍历到的结点最后一个输出,而最后一个遍历到的结点第一个输出。这就是典型的“后进先出”,我们可以用栈实现这种顺序。每经过一个结点的时候,把该结点放到一个栈中,当遍历完整个链表后,再从栈顶开始逐个输出结点的值,此时输出的结点的顺序已经反转过来了。这种思路的实现代码如下:
void PrintListReversingly_Iteratively(ListNode* pHead) { std::stack<ListNode*> nodes; ListNode* pNode = pHead; while(pNode != NULL) { nodes.push(pNode); pNode = pNode->m_pNext; } while(!nodes.empty()) { pNode = nodes.top(); printf("%d\t", pNode->m_nValue); nodes.pop(); } }
既然想到了用栈来实现这个函数,而递归在本质上就是一个栈结构,于是很自然的又想到了用递归来实现。要实现反过来输出链表,我们每访问到一个结点的时候,先递归输出它后面的结点,再输出该结点自身,这样链表的输出结果就反过来了。
基于这样的思路,不难写出如下代码:
void PrintListReversingly_Recursively(ListNode* pHead) { if(pHead != NULL) { if(pHead->m_pNext != NULL) { PrintListReversingly_Recursively(pHead->m_pNext); } printf(“%d\t”, pHead->m_nValue); } }
上面的基于递归的代码看起来很简洁,但有个问题:当链表非常长的时候,就会导致函数调用的层级很深,从而有可能导致函数调用栈溢出。显示用栈基于循环实现的代码的鲁棒性要好一些。
附上自己的代码:
(1) 头结点中的数据域不存放数据的
#include <stdio.h> #include <stdlib.h> struct LinkNode { int data; struct LinkNode *next; }; typedef struct LinkNode List; typedef List *LinkList; void Insert(LinkList &Head) { for (int i = 0; i < 10; i++) { LinkList tmp = (LinkList)malloc(sizeof(List)); if (tmp == NULL) printf("分配地址失败\n"); tmp->next = NULL; if (Head->next == NULL) { tmp->data = i; Head->next = tmp; } else { tmp->data = i; tmp->next = Head->next; Head->next = tmp; } } } // 由于 这种情况下 头结点 不存放数据;因此,打印时 不该打印头结点 的值 // 因此,先将 Head 指向 下一个结点 ,再调用 递归 void ReversePrint(LinkList Head) { if (Head != NULL && Head->next != NULL) { Head = Head->next; ReversePrint(Head); printf("%d\n", Head->data); } } void print(LinkList Head) { LinkList tmp = Head->next; while (tmp != NULL) { printf("%d\n", tmp->data); tmp = tmp->next; } } // 这个释放内存的函数 如有争议,可以直接留言 void myfree(LinkList &Head) { while (Head != NULL) { LinkList tmp = Head; Head = Head->next; free(tmp); tmp = NULL; } } int main() { LinkList Head = (LinkList)malloc(sizeof(List)); if (Head == NULL) printf("分配地址失败\n"); Head->next = NULL; Insert(Head); print(Head); printf("逆序打印\n"); ReversePrint(Head); myfree(Head); return 0; }
(2)头结点中的数据域存放数据的
#include <stdio.h> #include <stdlib.h> struct LinkNode { int data; struct LinkNode *next; }; typedef struct LinkNode List; typedef List *LinkList; void Insert(LinkList &Head) { for (int i = 1; i < 10; i++) { LinkList tmp = (LinkList)malloc(sizeof(List)); if (tmp == NULL) printf("分配地址失败\n"); tmp->next = NULL; if (Head->next == NULL) { tmp->data = i; Head->next = tmp; } else { tmp->data = i; tmp->next = Head->next; Head->next = tmp; } } } void ReversePrint(LinkList Head) { if (Head != NULL) { if (Head->next != NULL) { ReversePrint(Head->next); } printf("%d\n", Head->data); } } void print(LinkList Head) { LinkList tmp = Head; while (tmp != NULL) { printf("%d\n", tmp->data); tmp = tmp->next; } } void myfree(LinkList &Head) { while (Head != NULL) { LinkList tmp = Head; Head = Head->next; free(tmp); tmp = NULL; } } int main() { LinkList Head = (LinkList)malloc(sizeof(List)); if (Head == NULL) printf("分配地址失败\n"); Head->data = 0; Head->next = NULL; Insert(Head); print(Head); ReversePrint(Head); myfree(Head); return 0; }
相关文章推荐
- 【剑指offer】 面试题5: 从尾到头打印链表
- 【剑指Offer面试题】 九度OJ1511:从尾到头打印链表
- 剑指offer 面试题5:从尾到头打印链表
- 剑指offer--面试题5:从尾到头打印链表--Java实现
- 面试题5:从尾到头打印链表
- 剑指Offer面试题5(Java版):从尾到头打印链表
- 面试题5:从尾到头打印链表
- 面试题5:从尾到头打印链表
- 面试题:从尾到头打印链表
- 剑指offer《面试题5:从尾到头打印链表》
- 剑指offer-面试题05-从尾到头打印链表
- 剑指Offer学习之面试题5 : 从尾到头打印链表
- 剑指Offer(第二版)面试题6:从尾到头打印链表
- 剑指offer-面试题5-从尾到头打印链表
- 剑指Offer面试题5:从尾到头打印链表
- 面试题5 从尾到头打印链表
- 剑指offer面试题5——链表之从尾到头打印链表
- 剑指offer面试题5:从尾到头打印链表
- 【面试题】从尾到头打印链表&&链表中倒数第K个结点
- 【剑指offer】2.3.3链表——面试题5:从尾到头打印链表