遍历定义
遍历目的
遍历用途
遍历方法
算法描述
由二叉树的递归定义可知,遍历左子树和遍历右子树可如同遍历二叉树一样 递归 进行
若二叉树为空,则空操作;否则执行以下操作:
牢记按照 根左右 的顺序来进行遍历。每个结点的左子树的所有结点遍历完了之后才能轮到右子树。当一个结点的左右子树都为空的时候表示访问完毕。
算法实现
//前趋(先序)遍历
void Pre(BiTree* T)
{//二叉树及二叉树底下的所有子树中,//某一棵树不为空时,执行以下操作if(T != NULL){printf("%d\n",T -> data);//输出根节点的值pre(T -> lchile);//以同样的先序遍历的方法遍历左子树pre(T -> rchile);//以同样的先序遍历的方法遍历右子树//当左、右子树的某个结点为空时,//返回该结点的递归的上一层}
}
若二叉树为空,则空操作;否则执行以下操作:
每个结点的左子树按照左根右的顺序访问完了之后,才能访问根结点,最后按照 左根右 的顺序访问该结点的右子树的所有结点。
每个结点都按照左右根的顺序访问结点,每个结点的左子树按照左右根的顺序访问完所有结点之后,再到该结点的右子树按照左右根的顺序访问所有结点,最后访问该结点。
若二叉树为空,则空操作;否则执行以下操作:
已知二叉树的先序和中序序列,构造出相应的二叉树。
最后就剩个 J 结点,所以不用再往后分了。
至此,这棵二叉树构造完成。
已知一棵二叉树的中序和后序序列,请画出这棵二叉树。
/*二叉树的顺序存储*/
#include
#include#define MaxSize 100int data[MaxSize]; //数组存储树的结点,初始化为-1void init() //初始化数组
{for (int i = 0; i < MaxSize; i++){data[i]=-1;}
}//插入结点
void insert(int val)
{int i=1; //从根节点开始查找while (data[i]!=-1){ // 查找到空位置if(val
从上图看:
时间复杂度
空间复杂度
中序遍历非递归算法
基本思想:
例:
下图所示的一颗二叉树的非递归遍历
完整代码
#include
#include//定义二叉树结点结构体
typedef struct TreeNode{int data;struct TreeNode* left;struct TreeNode* right;}TreeNode;//定义栈结构体
typedef struct Stack{int top; //栈顶指针int capacity; //栈容量TreeNode **array; //栈数组,存放二叉树结点指针
}Stack;//创建二叉树结点
TreeNode* createNode(int data)
{TreeNode *node=(TreeNode*)malloc(sizeof(TreeNode)); //动态分配内存空间node->data=data; //赋值结点数据node->left=NULL; //初始化左右子结点为空node->right=NULL;return node; //返回新创建的结点
}//创建栈
Stack * createStack(int capacity)
{Stack *stack=(Stack*)malloc(sizeof(Stack)); //创建栈结构体stack->top=-1; //初始化栈顶指针stack->capacity=capacity; //设置栈容量stack->array=(TreeNode**)malloc(capacity * sizeof(TreeNode*)); //创建栈数组,存放二叉树结点指针return stack; //返回栈结构体指针
}//判断栈是否为空
int isEmpty(Stack* stack)
{return stack->top == -1; //当栈顶指针为-1时,说明栈为空
}//判断栈是否已满
int isFull(Stack* stack)
{return stack->top == stack->capacity -1 ; //当栈顶指针等于栈容量减1时,说明栈已满
}//入栈
void push(Stack* stack, TreeNode* node)
{if(isFull(stack)) //如果栈已满,则无法入栈{return ;}++stack->top;//栈顶指针先加1;然后将结点指针存放到栈顶stack->array[stack->top] = node;
}//出栈
TreeNode* pop(Stack* stack)
{if(isFull(stack)) //如果栈为空,则无法出栈{return NULL;}return stack->array[stack->top--]; //先取出栈顶结点指针,然后栈顶指针-1
}//中序遍历二叉树的非递归方法
void inorderTraversal(TreeNode* root)
{if(root == NULL) //如果根节点为空,则直接返回{return ;}Stack * stack= createStack(100); //创建一个栈,容量为100TreeNode * current =root; //初始化当前结点为根结点while(current != NULL || !isEmpty(stack)) //当当前结点不为空,或者栈不为空时,循环执行以下代码{//先将当前结点及其左子树全部入展while (current != NULL) //当前结点不为空时,将当前结点及其左子树全部入栈{push(stack,current); //将当前结点入栈current = current->left; //当前结点指向其左子节点}//已经遍历完了当前结点的所有左子节点,现在从栈中取出第一个结点current = pop(stack); //取出栈顶结点printf("%d",current->data); //输出该结点的值current = current->right; //将当前结点指向其右子结点,继续遍历右子树}
}int main(){//创建二叉树// 创建二叉树TreeNode* root = createNode(1);root->left = createNode(2);root->right = createNode(3);root->left->left = createNode(4);root->left->right = createNode(5);root->right->left = createNode(6);root->right->right = createNode(7);// 中序遍历二叉树inorderTraversal(root);return 0;
}
算法思路:使用一个队列
例如:
#include "stdlib.h"
#include "stdio.h"//定义二叉树结点结构体
struct TreeNode{int val; //结点的值struct TreeNode* left; //左子节点执照怎struct TreeNode* right; //右子结点指针
}TreeNode;//定义队列结构体
struct Queue{struct TreeNode* data; //存储结点指针的数组int front; //队头指针int rear; //队尾指针
} Queue;//初始化队列
void initQueue(struct Queue *q,int MaxSize )
{q->data=(struct TreeNode*)malloc(MaxSize * sizeof(struct TreeNode)); //申请数组空间q->front=0; //队头指针初始化为0q->rear=0; //队尾指针初始化为0
}//判断队列是否为空
int isEmpty(struct Queue* q)
{return q->front == q->rear; //当队头指针等于队尾指针时,队列为空
}//入队
void enQueue(struct Queue* q,struct TreeNode *node)
{q->data[q->rear]=*node; //将结点指针添加到队列尾部,并将队尾指针+1q->rear++; //队尾指针加一
}//出队
struct TreeNode* deQueue (struct Queue* q)
{return &q->data[q->front++]; //返回队头指针指向的结点指针,并将队头指针+1
}//创建二叉树
struct TreeNode *createTree()
{int val;scanf("%d",&val); //输入结点的值if(val == -1) //如果输入-1,表示该结点为空节点{return NULL;}struct TreeNode *node = (struct TreeNode*)malloc(sizeof(struct TreeNode)); //申请结点空间node->val=val; //赋值node->left = createTree(); //递归创建左子树node->right = createTree(); //递归创建右子树return node;
}//二叉树的层序遍历
void levelOrder(struct TreeNode* root)
{if(root == NULL) //判断是否为空树{return ;}struct Queue q; //定义队列initQueue (&q,100); //初始化队列enQueue(&q,root); //根节点入队while (!isEmpty(&q)) //队列不为空时{struct TreeNode* node = deQueue(&q); //取出队头指针指向的结点指针printf("%d",node->val); //输出结点的值if(node->left != NULL) //如果结点有左子节点将左子节点指针入队{enQueue(&q,node->left);}if (node->right != NULL) { //如果节点有右子节点,将右子节点指针入队enQueue(&q, node->right);}}
}// 测试
int main() {printf("请输入二叉树的节点,-1表示空节点:\n");struct TreeNode *root = createTree(); // 创建二叉树printf("层序遍历结果为:");levelOrder(root); // 二叉树的层序遍历printf("\n");return 0;
}
非递归代码实现
#include
#include // 定义二叉树节点结构体
struct TreeNode {int val; // 节点的值struct TreeNode *left; // 左子节点指针struct TreeNode *right; // 右子节点指针
};// 创建二叉树
struct TreeNode *createTree() {int val;struct TreeNode *root = NULL; // 根节点初始化为空struct TreeNode *curr = NULL; // 当前节点初始化为空struct TreeNode *parent = NULL; // 父节点初始化为空printf("请输入二叉树的节点,-1表示空节点:\n");while (scanf("%d", &val) == 1) { // 循环读入节点的值if (val == -1) { // 如果输入-1,表示该节点为空节点continue;}// 创建节点curr = (struct TreeNode *) malloc(sizeof(struct TreeNode));curr->val = val;curr->left = NULL;curr->right = NULL;// 判断是否为根节点if (root == NULL) {root = curr;} else {parent = root;while (1) { // 在树中查找节点的插入位置if (val < parent->val) {if (parent->left == NULL) {parent->left = curr;break;} else {parent = parent->left;}} else {if (parent->right == NULL) {parent->right = curr;break;} else {parent = parent->right;}}}}}return root; // 返回根节点指针
}// 层序遍历
void levelOrder(struct TreeNode *root) {if (root == NULL) {return;}// 定义一个队列,用于存储待访问的节点struct TreeNode **queue = (struct TreeNode **) malloc(sizeof(struct TreeNode *) * 1000);int front = 0, rear = 0;queue[rear++] = root; // 根节点入队while (front < rear) { // 当队列不为空时struct TreeNode *node = queue[front++]; // 出队一个节点printf("%d ", node->val); // 输出该节点的值if (node->left != NULL) { // 如果该节点有左子节点,将左子节点入队queue[rear++] = node->left;}if (node->right != NULL) { // 如果该节点有右子节点,将右子节点入队queue[rear++] = node->right;}}
}// 测试
int main() {struct TreeNode *root = createTree(); // 创建二叉树printf("层序遍历结果为:");levelOrder(root); // 二叉树的层序遍历printf("\n");return 0;
}
按照先序遍历序列建立二叉树的二叉链表。
例:已知先序序列为:A B C D E G F
#include "stdio.h"
#include "stdlib.h"//定义二叉树结点结构体
typedef struct TreeNode {int data ;struct TreeNode* left;struct TreeNode* right;
}TreeNode;//先序遍历顺序简历二叉链表
void createTree(TreeNode** node)
{int data ;scanf("%d",&data );if(data == -1){*node= NULL;}else{//创建新结点*node = (TreeNode*)malloc (sizeof(TreeNode));(*node)->data=data;//递归构建左右子树createTree(&((*node)->left));createTree(&((*node)->right));}
}//先序遍历二叉树
void preOrder(TreeNode* node)
{if(node != NULL){printf("%d",node->data);preOrder(node->left);preOrder(node->right);}
}int main()
{TreeNode* root = NULL;//读取先序遍历序列,构建二叉树printf("请输入先序遍历序列,用-1表示空节点:\n");createTree(&root);//输出二叉树的先序遍历结构printf("二叉树的先序遍历结果为:\n");preOrder(root);return 0;
}
#include
#include // 定义二叉树节点结构体
typedef struct node {int data;struct node* left;struct node* right;
} Node;// 创建节点
Node* create_node(int data) {// 分配内存空间Node* new_node = (Node*) malloc(sizeof(Node));// 初始化节点数据new_node->data = data;new_node->left = NULL;new_node->right = NULL;// 返回新节点return new_node;
}// 复制二叉树
Node* clone_tree(Node* root) {// 如果原树为空,则返回空if (root == NULL) {return NULL;} else {// 创建新节点并设置数据Node* new_root = create_node(root->data);// 递归复制左子树new_root->left = clone_tree(root->left);// 递归复制右子树new_root->right = clone_tree(root->right);// 返回新节点return new_root;}
}// 打印二叉树(先序遍历)
void print_tree(Node* root) {if (root != NULL) {// 打印当前节点的数据printf("%d ", root->data);// 递归打印左子树print_tree(root->left);// 递归打印右子树print_tree(root->right);}
}// 主函数
int main() {// 创建一个简单的二叉树Node* root = create_node(1);root->left = create_node(2);root->right = create_node(3);root->left->left = create_node(4);root->left->right = create_node(5);// 打印原始二叉树printf("Original tree: ");print_tree(root);printf("\n");// 复制二叉树Node* cloned_tree = clone_tree(root);// 打印复制的二叉树printf("Cloned tree: ");print_tree(cloned_tree);printf("\n");// 释放内存空间free(root->left->right);free(root->left->left);free(root->right);free(root->left);free(root);free(cloned_tree->left->right);free(cloned_tree->left->left);free(cloned_tree->right);free(cloned_tree->left);free(cloned_tree);return 0;
}/*在这个示例中,我们首先定义了一个Node结构体,表示二叉树的节点。我们使用create_node()函数创建节点,该函数使用给定的数据参数创建新节点,并将左右子节点初始化为NULL。然后,我们定义了clone_tree()函数来复制二叉树。这个函数使用递归的方式实现,首先创建一个新的根节点,并将它的值设置为原始根节点的值。然后,它递归调用clone_tree()函数来复制左右子树,并将它们分别设置为新节点的左右子节点。如果原始根节点为空,则函数返回NULL。最后,我们定义了print_tree()函数来打印二叉树。该函数使用先序遍历的方式打印节点的值。在main()函数中,我们创建了一个简单的二叉树,并使用print_tree()函数打印它。然后,我们使用clone_tree()函数复制该树,并再次使用print_tree()函数打印复制树的内容。*/
#include
#include // 定义二叉树结构体
struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
};// 计算二叉树的深度
int maxDepth(struct TreeNode* root) {if (root == NULL) { // 当前节点为空,深度为0return 0;}else { // 否则,递归计算左右子树的深度,并取较大值int leftDepth = maxDepth(root->left);int rightDepth = maxDepth(root->right);return (leftDepth > rightDepth) ? (leftDepth + 1) : (rightDepth + 1);}
}int main() {// 创建二叉树struct TreeNode *root = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->val = 1;root->left = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->left->val = 2;root->left->left = NULL;root->left->right = NULL;root->right = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->right->val = 3;root->right->left = NULL;root->right->right = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->right->right->val = 4;root->right->right->left = NULL;root->right->right->right = NULL;// 计算二叉树深度并输出结果int depth = maxDepth(root);printf("Depth of binary tree is %d\n", depth);return 0;
}/*
在 maxDepth 函数中,我们使用递归的方式计算二叉树的深度,首先判断当前节点是否为空,如果是,则深度为0;否则,递归计算左右子树的深度,并取较大值加1作为当前节点的深度。*/
如果是空树,则结点个数为 0。
反之结点个数为:左子树的结点个数 + 右子树的结点个数再 + 1(根节点)。
先求左子树的左子树,再加上左子树的右子树,最后加上左子树的根。
如:
#include
#include // 定义二叉树结构体
struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
};// 计算二叉树节点总个数
int countNodes(struct TreeNode* root) {if (root == NULL) { // 当前节点为空,节点个数为0return 0;}else { // 否则,递归计算左右子树节点个数,并加上当前节点int leftCount = countNodes(root->left);int rightCount = countNodes(root->right);return leftCount + rightCount + 1;}
}int main() {// 创建二叉树struct TreeNode *root = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->val = 1;root->left = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->left->val = 2;root->left->left = NULL;root->left->right = NULL;root->right = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->right->val = 3;root->right->left = NULL;root->right->right = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->right->right->val = 4;root->right->right->left = NULL;root->right->right->right = NULL;// 计算二叉树节点总个数并输出结果int count = countNodes(root);printf("Total number of nodes in binary tree is %d\n", count);return 0;
}
#include
#include // 定义二叉树结构体
struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
};// 计算二叉树中叶子节点数
int countLeaves(struct TreeNode* root) {if (root == NULL) { // 当前节点为空,叶子节点个数为0return 0;}else if (root->left == NULL && root->right == NULL) { // 当前节点没有左右子节点,是叶子节点return 1;}else { // 否则,递归计算左右子树的叶子节点个数,并返回总和int leftCount = countLeaves(root->left);int rightCount = countLeaves(root->right);return leftCount + rightCount;}
}int main() {// 创建二叉树struct TreeNode *root = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->val = 1;root->left = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->left->val = 2;root->left->left = NULL;root->left->right = NULL;root->right = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->right->val = 3;root->right->left = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->right->left->val = 4;root->right->left->left = NULL;root->right->left->right = NULL;root->right->right = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->right->right->val = 5;root->right->right->left = NULL;root->right->right->right = NULL;// 计算二叉树中叶子节点数并输出结果int count = countLeaves(root);printf("Total number of leaves in binary tree is %d\n", count);return 0;
}/*
上面的示例中,我们实现了一个名为 countLeaves 的函数,该函数用于计算给定二叉树中叶子节点的总个数。在 countLeaves 函数中,我们使用递归的方式计算二叉树中叶子节点的总个数,首先判断当前节点是否为空,如果是,则叶子节点个数为0;如果当前节点没有左右子节点,即为叶子节点,返回1;否则,递归计算左右子树中叶子节点的总个数,并返回总和。最后,我们在 main 函数中创建了一个二叉树,并调用 countLeaves 函数计算二叉树中叶子节点的总个数并输出结果。
*/
为什么要研究线索二叉树?
提出的问题
解决方法
举个栗子
为区分 lrchild 和 rchild 指针到底是指向孩子的指针,还是指针前趋或者后继的指针,对二叉链表中每个结点增加两个标志域 ltag
和 rtag
其中:
//二叉树的二叉线索存储表示
typedef struct BiThrNode
{int data;//数据域,存储数据元素本身int ltag,rtag;//左右标记域,存放 0 1struct BiThrNode* lchild,rchild;//左右孩子指针}BiThrNode,*BiThrTree;
先序线索二叉树
有了先序构造线索二叉树之后,中序、后序也是同样的道理。
#include
#include // 定义二叉树结构体
struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;int leftTag; // 左指针标记,0表示指向左子树,1表示指向前驱节点int rightTag; // 右指针标记,0表示指向右子树,1表示指向后继节点
};// 定义全局变量,用于记录最后一个访问的节点
struct TreeNode* lastVisited = NULL;// 对二叉树进行线索化
void createInOrderThread(struct TreeNode* root) {if (root == NULL) {return;}createInOrderThread(root->left); // 递归线索化左子树if (root->left == NULL) { // 如果左子树为空,将左指针标记为1,并指向前驱节点root->leftTag = 1;root->left = lastVisited;}if (lastVisited != NULL && lastVisited->right == NULL) { // 如果前驱节点的右指针为空,将右指针标记为1,并指向后继节点lastVisited->rightTag = 1;lastVisited->right = root;}lastVisited = root; // 更新最后访问的节点createInOrderThread(root->right); // 递归线索化右子树
}// 中序遍历线索化二叉树
void inOrderTraversal(struct TreeNode* root) {struct TreeNode *p = root;while (p != NULL) {while (p->leftTag == 0) { // 找到最左下的节点p = p->left;}printf("%d ", p->val); // 访问节点while (p->rightTag == 1) { // 如果右指针是线索,则遍历后继节点p = p->right;printf("%d ", p->val);}p = p->right; // 否则,遍历右子树}
}
// 释放二叉树的内存
void destroyTree(struct TreeNode* root) {if (root == NULL) {return;}destroyTree(root->left);destroyTree(root->right);free(root);
}//测试
int main() {// 创建线索二叉树struct TreeNode *root = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->val = 4;root->left = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->left->val = 2;root->left->left = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->left->left->val = 1;root->left->left->left = NULL;root->left->left->right = NULL;root->left->right = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->left->right->val = 3;root->left->right->left = NULL;root->left->right->right = NULL;root->right = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->right->val = 6;root->right->left = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->right->left->val = 5;root->right->left->left = NULL;root->right->left->right = NULL;root->right->right = (struct TreeNode*)malloc(sizeof(struct TreeNode));root->right->right->val = 7;root->right->right->left = NULL;root->right->right->right = NULL;// 对二叉树进行中序遍历线索化createInOrderThread(root);// 中序遍历线索化二叉树printf("Inorder traversal of threaded binary tree: ");inOrderTraversal(root);printf("\n");// 释放二叉树内存destroyTree(root);return 0;
}