面试题 5,从尾到头打印链表 (链表系列)

注意链表本身没有prev指针。
解法a.
定义指针p1,再定义指针P。
循环开始,p1从头节点开始遍历,而指针P用来存储已经打印出来的节点地址。
当p1->m_pNext节点地址和P相等时,打印p1节点所在的值。P的值改成p1的地址。
重新循环。
这个方法的时间复杂度为O(N^2)
需要考虑只有一个节点,和输入空指针(没有节点)的边界情况,代码:
void PrintReversely(ListNode *pHead){ if(pHead != null){ if(pHead -> m_pNext == null){ printf("%d\n",pHead -> m_nKey); }else{ ListNode *p1 = phead; ListNode *P = null; while(P != phead -> m_pNext){ p1 = phead; while(p1 -> m_pNext != P){ p1 = p1 -> m_pNext; } printf("%d\n",p1 -> m_nKey); P = p1; } printf("%d\n",p1 -> m_nKey); //输出头节点的值 } } }
写完后发现只有一个节点的边界情况已经包含else中,因此最外层if判断可以省略,省略后的代码:
void PrintReversely(ListNode *pHead){ if(pHead != null){ ListNode *p1 = phead; ListNode *P = null; while(P != phead -> m_pNext){ p1 = phead; while(p1 -> m_pNext != P){ p1 = p1 -> m_pNext; } printf("%d\n",p1 -> m_nKey); P = p1; } printf("%d\n",p1 -> m_nKey); //输出头节点的值 } }
解法b.
如果想降低时间复杂度,那可以使用以空间换时间的做法。链表的遍历只能从头到尾,而输出是越往后越先输出,因此采用先进后出的栈来临时存放遍历过的结点值。
代码:
void PrintReverselyStack(ListNode *pHead){ std::Stack<int> stack; ListNode *p1 = phead; while(null != p1){ stack.push(p1 -> m_nKey); p1 = p1 -> m_pNext; } while(!stack.empty()){ printf("%d\n",stack.top()); stack.pop(); } }
时间复杂度O(N)
当然,也能用递归来实现,代码(错误):
void PrintReverselyRecursive(ListNode *pHead){ if(null != pHead -> m_pNext){ PrintReverselyRecursive(pHead -> m_pNext); } printf("%d\n",pHead -> m_nKey); }
此代码的错误之处在于又没有考虑空指针输入。
改正:
void PrintReverselyRecursive(ListNode *pHead){ if(null != pHead){ if(null != pHead -> m_pNext){ PrintReverselyRecursive(pHead -> m_pNext); } printf("%d\n",pHead -> m_nKey); } }
递归的代码相对比较简洁,但是递归调用的缺陷在于,如果链表非常长,会让函数递归调用的层次很深,从而导致函数栈溢出。
因此使用栈更加安全些。
最后,做链表题时,一定不要忘掉考虑空指针的输入情况!
------------------------------------------------
Felix原创,转载请注明出处,感谢博客园!
posted on 2013-11-25 11:36 Felix Fang 阅读(131) 评论(0) 收藏 举报
浙公网安备 33010602011771号