题目——输入一个链表的头节点,从尾到头反过来打印出每个结点的值。(打印链表的值只是一个可读操作,最好不要修改链表的结构)
算法1——利用栈“先进后出”
分析:遍历是从头到尾访问结点中的value,而打印却是从尾到头。也就是说第一个遍历到的结点需要最后一个输出,最后一个遍历到的结点需要第一个输出,以此看来可以用到栈的特性“先进后出”。每次遍历一个结点,将其结点的value入栈,等遍历完所有结点,再将栈中的值以此出栈,那value值的顺序刚好逆序输出。
算法2——“递归”
分析:递归在本质上就是一个栈结构,从头开始每访问一个结点,先递归输出它后面的结点
注意:如果链表很长,使得递归调用层次很深,可能会导致函数调用栈溢出。基于循环的代码显式用栈鲁棒性好一点。
两个算法的代码如下:
#include<iostream>
#include<stack>
#include<assert.h>
using namespace std;
struct ListNode
{
int m_value;
ListNode* m_pNext;
};
void InitList(ListNode* pHead)
{
assert(pHead != NULL);
pHead->m_pNext = NULL;
}
void PrintListendtobegin1(ListNode* pHead)//算法1
{
if (pHead == NULL)
{
return;
}
stack<ListNode*> Node;
ListNode* ptr = pHead->m_pNext;//从第一个结点开始(不是头节点)
while (ptr != NULL)//从第一个开始遍历并将结点逐一入栈
{
Node.push(ptr);
ptr = ptr->m_pNext;
}
while (!Node.empty())//栈不为空时,循环获取栈顶结点,打印结点的value值后,将此节点出栈
{
ptr = Node.top();
cout << ptr->m_value << " ";
Node.pop();
}
cout << endl;
}
void PrintListendtobegin2(ListNode* pHead)//算法2
{
if (pHead != NULL)
{
if (pHead->m_pNext != NULL)
{
PrintListendtobegin2(pHead->m_pNext);
}
cout << pHead->m_value << " ";
}
}
int main()
{
ListNode ListHead;//定义一个链表
InitList(&ListHead);//初始化链表
ListNode* p;
ListNode* head = &ListHead;//定义一个指向链表头节点的指针,用作插入新节点
int value;
for (int i = 5; i > 0; --i)//头插法插入新节点
{
p = (ListNode*)malloc(sizeof(ListNode));
assert(p != NULL);
p->m_value = i;
p->m_pNext = head->m_pNext;
head->m_pNext = p;
}
//PrintListendtobegin1(&ListHead);
ListNode* ph = (&ListHead)->m_pNext;
PrintListendtobegin2(ph);
}