給定一個二叉樹,返回它的 前序 遍歷。
示例:
輸入: [1,null,2,3] 1 \ 2 / 3 輸出: [1,2,3]
進階: 遞歸算法很簡單,你可以通過迭代算法完成嗎?
前序遍歷
前序遍歷首先訪問根節點,然后遍歷左子樹,最后遍歷右子樹。
用c語言來實現比較麻煩,現在大概介紹下我的思路,首先題目先要實現一個前序遍歷,如果用遞歸,會比較簡單,幾行代碼就可以實現,但是現在要求使用迭代發來實現。整個遍歷過程是,訪問根節點,然后遍歷其左子樹,然后再看左子樹是否有其左孩子和右孩子。因為在查看左孩子之后,還要再查看根節點的右孩子,所以每次需要把根節點記錄下來,需要存在棧中。所以我們需要實現一個棧,有壓棧和出棧操作。另外我們需要一個鏈表來存放已經訪問過的節點,到最后,需要把這些節點統一存儲到一個數組中,然后返回。
下面來看下我碼的代碼
/* 鏈表節點 用於存儲輸出結果 */ struct listNode { int val; struct listNode *next; }; struct list { int count; struct listNode *head; struct listNode *tail; }; /* 棧節點,用於存儲已經遍歷過的根節點 */ struct StackNode { void *entry; struct StackNode *next; }; struct stack { struct StackNode *top; }; void init_stack(struct stack *s) { s->top = NULL; } void stack_push(struct stack *s, void *np) { struct StackNode *node = malloc(sizeof(struct StackNode)); node->entry = np; node->next = s->top; s->top = node; }; void *stack_pop(struct stack *s) { struct StackNode *np = s->top; void *node = np->entry; s->top = np->next; free(np); return node; }; bool isEmpty(struct stack *s) { return (s->top == NULL) ? true : false; } void init_list(struct list *l) { l->count = 0; l->head = NULL; l->tail = NULL; } void add_new_node(struct list *l, struct listNode *node) { if (!l->head) { l->head = node; l->tail = node; l->count = 1; return; } l->tail->next = node; l->tail = node; l->count++; }
這些是輔助函數
int* preorderTraversal(struct TreeNode* root, int* returnSize){ struct TreeNode *pNode = root; struct listNode *newNode = NULL; struct list *l = malloc(sizeof(struct list)); struct stack *s = malloc(sizeof(struct stack)); int *r = NULL; int i = 0; struct listNode *head = NULL; init_list(l); init_stack(s); while (pNode != NULL || !isEmpty(s)) { if (pNode != NULL) { newNode = malloc(sizeof(struct listNode)); newNode->val = pNode->val; newNode->next = NULL; add_new_node(l, newNode); stack_push(s, (void *)pNode); pNode = pNode->left; } else { pNode = (struct TreeNode *)stack_pop(s); pNode = pNode->right; } } r = malloc(sizeof(int) * l->count); head = l->head; while(head && i < l->count) { r[i] = head->val; i++; head = head->next; } *returnSize = l->count; return r; }
這個是具體的前序遍歷函數。
對應的中序遍歷的核心代碼如下:
while (pNode != NULL || !isEmpty(s))
{
if (pNode != NULL) { stack_push(s, (void *)pNode); pNode = pNode->left; } else { pNode = (struct TreeNode *)stack_pop(s); newNode = malloc(sizeof(struct listNode)); newNode->val = pNode->val; newNode->next = NULL; add_new_node(l, newNode); pNode = pNode->right; } }
后序遍歷如下:
while (pNode != NULL || !isEmpty(s))
{
if (pNode != NULL) { stack_push(s, (void *)pNode); pNode = pNode->left; } else { seek = (struct TreeNode *)stack_seek(s); if (seek->right == NULL || last == seek->right) { stack_pop(s); newNode = malloc(sizeof(struct listNode)); newNode->val = seek->val; newNode->next = NULL; add_new_node(l, newNode); last = seek; } else { pNode = seek->right; } } }