在 C 语言中实现树的遍历主要有以下几种方法:
前序遍历(递归)
-
思路 :先访问根节点,再递归地前序遍历左子树,最后递归地前序遍历右子树。
-
示例代码 :
#include <stdio.h> // 定义树的节点结构 typedef struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; } TreeNode; // 前序遍历函数 void preorderTraversal(TreeNode* root) { if (root == NULL) { return; } // 访问根节点 printf("%d ", root->val); // 递归遍历左子树 preorderTraversal(root->left); // 递归遍历右子树 preorderTraversal(root->right); } // 测试函数 int main() { // 创建树的节点 TreeNode root; root.val = 1; TreeNode leftChild; leftChild.val = 2; TreeNode rightChild; rightChild.val = 3; TreeNode leftLeftGrandchild; leftLeftGrandchild.val = 4; TreeNode leftRightGrandchild; leftRightGrandchild.val = 5; // 构建树的结构 root.left = &leftChild; root.right = &rightChild; leftChild.left = &leftLeftGrandchild; leftChild.right = &leftRightGrandchild; rightChild.left = NULL; rightChild.right = NULL; // 进行前序遍历 printf("前序遍历结果:"); preorderTraversal(&root); printf("\n"); return 0; }
中序遍历(递归)
-
思路 :先递归地中序遍历左子树,再访问根节点,最后递归地中序遍历右子树。
-
示例代码 :
#include <stdio.h> // 定义树的节点结构 typedef struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; } TreeNode; // 中序遍历函数 void inorderTraversal(TreeNode* root) { if (root == NULL) { return; } // 递归遍历左子树 inorderTraversal(root->left); // 访问根节点 printf("%d ", root->val); // 递归遍历右子树 inorderTraversal(root->right); } // 测试函数 int main() { // 创建树的节点和构建树的结构(与前序遍历示例相同) TreeNode root; root.val = 1; TreeNode leftChild; leftChild.val = 2; TreeNode rightChild; rightChild.val = 3; TreeNode leftLeftGrandchild; leftLeftGrandchild.val = 4; TreeNode leftRightGrandchild; leftRightGrandchild.val = 5; root.left = &leftChild; root.right = &rightChild; leftChild.left = &leftLeftGrandchild; leftChild.right = &leftRightGrandchild; rightChild.left = NULL; rightChild.right = NULL; // 进行中序遍历 printf("中序遍历结果:"); inorderTraversal(&root); printf("\n"); return 0; }
后序遍历(递归)
-
思路 :先递归地后序遍历左子树,再递归地后序遍历右子树,最后访问根节点。
-
示例代码 :
#include <stdio.h> // 定义树的节点结构 typedef struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; } TreeNode; // 后序遍历函数 void postorderTraversal(TreeNode* root) { if (root == NULL) { return; } // 递归遍历左子树 postorderTraversal(root->left); // 递归遍历右子树 postorderTraversal(root->right); // 访问根节点 printf("%d ", root->val); } // 测试函数 int main() { // 创建树的节点和构建树的结构(与前序遍历示例相同) TreeNode root; root.val = 1; TreeNode leftChild; leftChild.val = 2; TreeNode rightChild; rightChild.val = 3; TreeNode leftLeftGrandchild; leftLeftGrandchild.val = 4; TreeNode leftRightGrandchild; leftRightGrandchild.val = 5; root.left = &leftChild; root.right = &rightChild; leftChild.left = &leftLeftGrandchild; leftChild.right = &leftRightGrandchild; rightChild.left = NULL; rightChild.right = NULL; // 进行后序遍历 printf("后序遍历结果:"); postorderTraversal(&root); printf("\n"); return 0; }
前序遍历(非递归)
-
思路 :使用栈来辅助遍历。先将根节点压入栈中,然后循环执行以下操作:弹出栈顶节点并访问,若该节点有右孩子则将右孩子压入栈,若该节点有左孩子则将左孩子压入栈。
-
示例代码 :
#include <stdio.h> #include <stdlib.h> // 定义树的节点结构 typedef struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; } TreeNode; // 定义栈的节点结构 typedef struct StackNode { TreeNode* treeNode; struct StackNode* next; } StackNode; // 定义栈结构 typedef struct Stack { StackNode* top; } Stack; // 初始化栈 void initStack(Stack* stack) { stack->top = NULL; } // 判断栈是否为空 int isEmpty(Stack* stack) { return stack->top == NULL; } // 入栈操作 void push(Stack* stack, TreeNode* treeNode) { StackNode* newNode = (StackNode*)malloc(sizeof(StackNode)); newNode->treeNode = treeNode; newNode->next = stack->top; stack->top = newNode; } // 出栈操作 TreeNode* pop(Stack* stack) { if (isEmpty(stack)) { return NULL; } StackNode* temp = stack->top; TreeNode* treeNode = temp->treeNode; stack->top = temp->next; free(temp); return treeNode; } // 前序遍历函数(非递归) void preorderTraversalNonRecursive(TreeNode* root) { if (root == NULL) { return; } Stack stack; initStack(&stack); push(&stack, root); while (!isEmpty(&stack)) { TreeNode* node = pop(&stack); printf("%d ", node->val); // 先右后左压栈,保证出栈顺序是左右 if (node->right) { push(&stack, node->right); } if (node->left) { push(&stack, node->left); } } } // 测试函数 int main() { // 创建树的节点和构建树的结构(与前序遍历示例相同) TreeNode root; root.val = 1; TreeNode leftChild; leftChild.val = 2; TreeNode rightChild; rightChild.val = 3; TreeNode leftLeftGrandchild; leftLeftGrandchild.val = 4; TreeNode leftRightGrandchild; leftRightGrandchild.val = 5; root.left = &leftChild; root.right = &rightChild; leftChild.left = &leftLeftGrandchild; leftChild.right = &leftRightGrandchild; rightChild.left = NULL; rightChild.right = NULL; // 进行前序遍历(非递归) printf("前序遍历(非递归)结果:"); preorderTraversalNonRecursive(&root); printf("\n"); return 0; }
中序遍历(非递归)
-
思路 :同样使用栈来辅助遍历。初始化时将根节点压入栈中,然后循环执行以下操作:一直向左子树移动并压栈,直到左子树为空,然后弹出栈顶节点并访问,接着将当前节点指向该节点的右孩子,重复上述过程。
-
示例代码 :
#include <stdio.h> #include <stdlib.h> // 定义树的节点结构 typedef struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; } TreeNode; // 定义栈的节点结构和栈结构(与前序遍历非递归示例相同) typedef struct StackNode { TreeNode* treeNode; struct StackNode* next; } StackNode; typedef struct Stack { StackNode* top; } Stack; void initStack(Stack* stack) { stack->top = NULL; } int isEmpty(Stack* stack) { return stack->top == NULL; } void push(Stack* stack, TreeNode* treeNode) { StackNode* newNode = (StackNode*)malloc(sizeof(StackNode)); newNode->treeNode = treeNode; newNode->next = stack->top; stack->top = newNode; } TreeNode* pop(Stack* stack) { if (isEmpty(stack)) { return NULL; } StackNode* temp = stack->top; TreeNode* treeNode = temp->treeNode; stack->top = temp->next; free(temp); return treeNode; } // 中序遍历函数(非递归) void inorderTraversalNonRecursive(TreeNode* root) { if (root == NULL) { return; } Stack stack; initStack(&stack); TreeNode* current = root; while (current != NULL || !isEmpty(&stack)) { // 一直向左子树移动并压栈 while (current != NULL) { push(&stack, current); current = current->left; } // 弹出栈顶节点并访问 current = pop(&stack); printf("%d ", current->val); // 转向右子树 current = current->right; } } // 测试函数 int main() { // 创建树的节点和构建树的结构(与前序遍历示例相同) TreeNode root; root.val = 1; TreeNode leftChild; leftChild.val = 2; TreeNode rightChild; rightChild.val = 3; TreeNode leftLeftGrandchild; leftLeftGrandchild.val = 4; TreeNode leftRightGrandchild; leftRightGrandchild.val = 5; root.left = &leftChild; root.right = &rightChild; leftChild.left = &leftLeftGrandchild; leftChild.right = &leftRightGrandchild; rightChild.left = NULL; rightChild.right = NULL; // 进行中序遍历(非递归) printf("中序遍历(非递归)结果:"); inorderTraversalNonRecursive(&root); printf("\n"); return 0; }
后序遍历(非递归)
-
思路 :使用两个栈来辅助遍历。先将根节点压入第一个栈中,然后循环执行以下操作:弹出栈顶节点并压入第二个栈,若该节点有左孩子则将左孩子压入第一个栈,若该节点有右孩子则将右孩子压入第一个栈。最后,依次弹出第二个栈中的节点并访问。
-
示例代码 :
#include <stdio.h> #include <stdlib.h> // 定义树的节点结构 typedef struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; } TreeNode; // 定义栈的节点结构和栈结构(与前序遍历非递归示例相同) typedef struct StackNode { TreeNode* treeNode; struct StackNode* next; } StackNode; typedef struct Stack { StackNode* top; } Stack; void initStack(Stack* stack) { stack->top = NULL; } int isEmpty(Stack* stack) { return stack->top == NULL; } void push(Stack* stack, TreeNode* treeNode) { StackNode* newNode = (StackNode*)malloc(sizeof(StackNode)); newNode->treeNode = treeNode; newNode->next = stack->top; stack->top = newNode; } TreeNode* pop(Stack* stack) { if (isEmpty(stack)) { return NULL; } StackNode* temp = stack->top; TreeNode* treeNode = temp->treeNode; stack->top = temp->next; free(temp); return treeNode; } // 后序遍历函数(非递归) void postorderTraversalNonRecursive(TreeNode* root) { if (root == NULL) { return; } Stack stack1, stack2; initStack(&stack1); initStack(&stack2); push(&stack1, root); while (!isEmpty(&stack1)) { TreeNode* node = pop(&stack1); push(&stack2, node); // 先左后右压栈,保证出栈顺序是左右 if (node->left) { push(&stack1, node->left); } if (node->right) { push(&stack1, node->right); } } // 弹出 stack2 中的节点并访问 while (!isEmpty(&stack2)) { TreeNode* node = pop(&stack2); printf("%d ", node->val); } } // 测试函数 int main() { // 创建树的节点和构建树的结构(与前序遍历示例相同) TreeNode root; root.val = 1; TreeNode leftChild; leftChild.val = 2; TreeNode rightChild; rightChild.val = 3; TreeNode leftLeftGrandchild; leftLeftGrandchild.val = 4; TreeNode leftRightGrandchild; leftRightGrandchild.val = 5; root.left = &leftChild; root.right = &rightChild; leftChild.left = &leftLeftGrandchild; leftChild.right = &leftRightGrandchild; rightChild.left = NULL; rightChild.right = NULL; // 进行后序遍历(非递归) printf("后序遍历(非递归)结果:"); postorderTraversalNonRecursive(&root); printf("\n"); return 0; }
以上是 C 语言中实现树的遍历的常见方法,你可以根据实际需求选择合适的遍历方式。