递归中序树遍历
顺序、深度优先的树遍历不需要显式堆栈。递归使用进程的调用堆栈作为隐式数据结构。您提供的代码实际上是这样做的,尽管它似乎将堆栈推送/弹出和递归调用混为一谈,并且忽略了对root.
这是一个最小的例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int data;
struct node *left;
struct node *right;
};
void printInOrder(struct node *root) {
if (root) {
printInOrder(root->left);
printf("%d\n", root->data);
printInOrder(root->right);
}
}
struct node *newNode(int data) {
struct node *result = malloc(sizeof(*result));
memset(result, 0, sizeof(*result));
result->data = data;
return result;
}
void freeTree(struct node *root) {
if (root) {
freeTree(root->left);
freeTree(root->right);
free(root);
}
}
int main() {
/* 0
/ \
1 2
/ \
3 4
/ \ / \
5 6 7 8 */
struct node *root = newNode(0);
root->left = newNode(1);
root->right = newNode(2);
root->left->left = newNode(3);
root->left->left->left = newNode(5);
root->left->left->right = newNode(6);
root->left->right = newNode(4);
root->left->right->left = newNode(7);
root->left->right->right = newNode(8);
printInOrder(root);
freeTree(root);
return 0;
}
迭代中序树遍历
如果您确实需要迭代地执行此操作,那么您将比递归版本做更多的工作。
第一个设计选择是使堆栈在printInOrder函数内部并使用简单的数组还是编写堆栈类。编写一个堆栈类需要做更多的工作,但它是可重用的(看起来你已经走上了这条路)。
至于您现有的函数头,强制调用者分配应该在函数调用内部的资源有点不寻常;理想情况下,printInOrder它是一个通用的、无状态的黑匣子,调用者可以信任它来完成其工作而不会产生副作用。
想象一下,使用同一个堆栈进行多次调用printInOrder可能会导致令人惊讶的结果,或者调用者不得不担心这个堆栈的分配/释放。
遍历算法也变得更加复杂。我们不需要在循环中打印节点的数据,而是将其压入堆栈并遍历其左子节点,重复直到当前节点为空。然后我们可以打印栈顶,并使当前节点成为刚刚打印的节点的右孩子。重复直到堆栈耗尽。
这是具有内部堆栈的迭代算法,可作为上述代码示例的插件:
void printInOrder(struct node *root) {
int capacity = 4;
int top = 0;
struct node **stack = malloc(sizeof(*stack) * capacity);
for (stack[top] = root; top >= 0;) {
for (root = stack[top--]; root; root = root->left) {
if (top >= capacity &&
!(stack = realloc(stack, sizeof(stack) * (capacity *= 2)))) {
fprintf(stderr, "%s [%d] realloc failed\n", __FILE__, __LINE__);
exit(1);
}
stack[++top] = root;
}
if (top >= 0) {
root = stack[top--];
printf("%d\n", root->data);
stack[++top] = root->right;
}
}
free(stack);
}
这是一个使用堆栈类的版本。逻辑更清晰,但我们引入了依赖项。
stack.h
#ifndef STACK_H
#define STACK_H
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
struct stack {
int top;
int capacity;
void **entries;
};
struct stack *createStack(int capacity) {
if (capacity <= 0) return NULL;
struct stack *s = malloc(sizeof(*s));
s->top = -1;
s->capacity = capacity;
s->entries = malloc(sizeof(*s->entries) * capacity);
return s;
}
bool empty(struct stack *s) {
return s->top < 0;
}
void freeStack(struct stack *s) {
free(s->entries);
free(s);
}
void *pop(struct stack *stack) {
if (stack->top < stack->capacity / 2 - 1) {
stack->entries = realloc(stack->entries,
sizeof(stack->entries) *
(stack->capacity /= 2));
if (!stack->entries) {
fprintf(stderr, "%s [%d] realloc failed\n", __FILE__, __LINE__);
exit(1);
}
}
return stack->entries[stack->top--];
}
void push(struct stack *stack, void *data) {
if (stack->top >= stack->capacity) {
stack->entries = realloc(stack->entries,
sizeof(stack->entries) *
(stack->capacity *= 2));
if (!stack->entries) {
fprintf(stderr, "%s [%d] realloc failed\n", __FILE__, __LINE__);
exit(1);
}
}
stack->entries[++stack->top] = data;
}
#endif
main.c
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
struct node {
int data;
struct node *left;
struct node *right;
};
void printInOrder(struct node *root) {
struct stack *stack = createStack(4);
for (push(stack, root); !empty(stack);) {
for (root = pop(stack); root; root = root->left) {
push(stack, root);
}
if (!empty(stack)) {
root = pop(stack);
printf("%d\n", root->data);
push(stack, root->right);
}
}
freeStack(stack);
}
struct node *newNode(int data) {
struct node *result = malloc(sizeof(*result));
memset(result, 0, sizeof(*result));
result->data = data;
return result;
}
void freeTree(struct node *root) {
if (root) {
freeTree(root->left);
freeTree(root->right);
free(root);
}
}
int main() {
/* 0
/ \
1 2
/ \
3 4
/ \ / \
5 6 7 8 */
struct node *root = newNode(0);
root->left = newNode(1);
root->right = newNode(2);
root->left->left = newNode(3);
root->left->left->left = newNode(5);
root->left->left->right = newNode(6);
root->left->right = newNode(4);
root->left->right->left = newNode(7);
root->left->right->right = newNode(8);
printInOrder(root);
freeTree(root);
return 0;
}