標籤:鏈表 遞迴 棧
題目描述:
輸入一個鏈表的頭結點,從尾到頭反過來列印出每個結點的值。鏈表結點定義如下:
struct ListNode{
int m_nKey;
ListNode *m_pNext;
};
分析描述:
對於鏈表,如果是從頭到尾的列印出鏈表是比較容易,但如果是從尾到頭返過來列印每個結點的值就比較複雜。反序輸出就是第一個遍曆到的結點最後一個輸出,而最後一個遍曆的結點第一個輸出。
這就是典型的“後進先出”,可以想到的方法一是用棧實現這種順序。沒經過一個結點的時候,把該結點放到一個棧中。當遍曆完整個鏈表後,再從棧頂開始逐個輸出結點的值。此時輸出的結點的順序已經反轉過來了。
遞迴在本質上就是一個棧結構,所以很自然的想到用遞迴來實現。要實現反過來輸出鏈表,我們每訪問到一個結點的時候,先遞迴輸出它後面的結點,再輸出該結點自身,這樣鏈表的輸出結果就反過來了。但有個問題:當鏈表非常長的時候,就會導致函數調用的層級很深,從而有可能導致函數調用棧的溢出。
程式樣本:
1、用棧實現的“從尾到頭列印鏈表”程式碼如下:
#include <stdio.h>#include <stdlib.h>#include <memory.h>#ifndef ERROR#define ERROR (0)#endif#ifndef OK#define OK(!ERROR)#endif#define STACK_INIT_SIZE 100#define STACKINCREMENT 10typedef int ElemType;typedef struct Node{ElemType data;struct Node *next;}Node, *pNode;typedef int SElemType;typedef struct SqStack{SElemType*base;SElemType*top;intstacksize;}SqStack, *pStack;pStack S;pStack InitStack(pStack S){S = (pStack)malloc(STACK_INIT_SIZE * sizeof(SElemType));if(S == NULL){return ERROR;}S->base = (SElemType *)S;S->top = S->base;S->stacksize = STACK_INIT_SIZE;return S;}pStack Push(pStack S, SElemType e){if((S->top - S->base) >= S->stacksize){S->base = (SElemType *)realloc(S, (S->stacksize + STACKINCREMENT) * sizeof(SElemType));if(S->base == NULL)return ERROR;S->top = S->base + S->stacksize;S->stacksize += STACKINCREMENT;}*S->top++ = e;return S;}SElemType Pop(pStack S){if(S->top == S->base)return 0;return *(--S->top);}pNode CreateList(){ElemType val;pNode pHead = NULL;pNode pCur = NULL;do{scanf("%d", &val);if(val != -1){pNode pNew = (pNode)malloc(sizeof(Node));if(pNew == NULL)exit(EXIT_FAILURE);pNew->data = val;pNew->next = NULL;if(pHead == NULL){pHead = pNew;pCur = pHead;}else{pCur->next = pNew;pCur = pCur->next;}}}while(val != -1);return pHead;}void DestroyList(pNode pHead){if(pHead == NULL)return ;pNode p = NULL;while(pHead != NULL){p = pHead->next;free(pHead);pHead = p;}}void PrintListReverse(pNode pHead){if(pHead == NULL)return;pNode TmpNode = pHead;pStack S = InitStack(S);while(TmpNode != NULL){Push(S, TmpNode->data);TmpNode = TmpNode->next;}while(S->top != S->base){printf("%d", Pop(S));}}intmain(int argc, char **argv){pNode pHead = CreateList();PrintListReverse(pHead);DestroyList(pHead);return 0;}
2、用遞迴實現的“從尾到頭列印鏈表”程式碼如下:
#include <stdio.h>#include <stdlib.h>typedef int ElemType;typedef struct Node{ElemType data;struct Node *next;}Node, *pNode;void PrintListReverse(pNode pHead){if(pHead == NULL)return;if(pHead->next != NULL)PrintListReverse(pHead->next);printf("%d\n", pHead->data);}pNode CreateList(){ElemType val;pNode pHead = NULL;pNode pCur = NULL;do{scanf("%d", &val);if(val != -1){pNode pNew = (pNode)malloc(sizeof(Node));if(pNew == NULL)exit(EXIT_FAILURE);pNew->data = val;pNew->next = NULL;if(pHead == NULL){pHead = pNew;pCur = pHead;}else{pCur->next = pNew;pCur = pCur->next;}}}while(val != -1);return pHead;}void DestroyList(pNode pHead){if(pHead == NULL)return ;pNode p = NULL;while(pHead != NULL){p = pHead->next;free(pHead);pHead = p;}}intmain(int argc, char **argv){pNode pHead = CreateList();PrintListReverse(pHead);DestroyList(pHead);return 0;}
總結:
1、對於反向輸出時,應該考慮它的特性,選擇資料結構類型進行實現。一定要搞清楚各種資料結構類型的特點。
2、對於棧能實現的例子,一般要想到也可以用遞迴來完成。遞迴的缺點就是遞迴層級很深時,可能導致函數調用棧溢出。
注意上面的第一個程式有點小小的bug,另外本篇參考:http://blog.csdn.net/ns_code/article/details/25028525