C/C++ 数据结构与算法【树和二叉树】 树和二叉树,二叉树先中后序遍历详细解析【日常学习,考研必备】带图+详细代码

一、树介绍

在这里插入图片描述

在这里插入图片描述

1)树的定义

树 (Tree) 是n(n≥0) 个结点的有限集。

若n = 0,称为空树;

若n > 0,则它满足如下两个条件:

(1)有且仅有一个特定的称为(Root)的结点;

(2)其余结点可分为m(m≥0)个互不相交的有限集 T1,T2,T3,…,Tm,其中每一个集合本身又是一棵树,并称为根的子树(SubTree)。

2)树的表示方式

在这里插入图片描述

在这里插入图片描述

3)树的基本术语

在这里插入图片描述

1、树的深度

在这里插入图片描述

2、有序树和无序树

在这里插入图片描述

3、森林

在这里插入图片描述

4)树结构于线性结构的比较

在这里插入图片描述

二、二叉树

1)二叉树的定义

为何要重点研究每结点最多只有两个 “又” 的树?

  • 二叉树的结构最简单,规律性最强;
  • 可以证明,所有树都能转为唯一对应的不失一般性。

普通树(多叉树)若不转化为二叉树,则运算很难实现。

二叉树在树结构的应用中起着非常重要的作用,因为对二叉的许多操作算法简单,而任何树都可以与二叉树相互转换,这样就解决了树的存储结构及其运算中存在的复杂性。

二叉树是 n(n≥0)个结点的有限集,它或者是空集(n =0),或者由一个根结点及两棵互不相交的分别称作这个根的左子树和右子树的二又树组成。

特点:

  1. 每个结点最多有俩孩子(二又树中不存在度大于 2 的结点)。
  2. 子树有左右之分,其次序不能颠倒。
  3. 二叉树可以是空集合,根可以有空的左子树或空的右子树。

注意:

二叉树不是树的特殊情况,它们是两个概念。

  • 二叉树结点的子树要区分左子树和右子树,即使只有一棵子树行区分,说明它是左子树,还是右子树。
  • 树当结点只有一个孩子时,就无须区分它是左还是右的次序。因此二者是不同的。这是二又树与树的最主要的差别。

在这里插入图片描述

(也就是二叉树每个结点位置或者说次序都是固定的,可以是空,但是不可以说它没有位置,而树的结点位置是相对于别的结点来说的,

没有别的结点时,它就无所谓左右了)

2)二叉树的5种基本形态

在这里插入图片描述

注意:虽然二叉树与树概念不同,但有关树的基本术语对二叉树都适用。

3)二叉树的抽象数据类型定义

在这里插入图片描述
在这里插入图片描述

4)二叉树的性质

1、性质1

第 i 层至少有1个结点

在这里插入图片描述

2、性质2

深度为k时至少有k个结点

在这里插入图片描述

3、性质3

在这里插入图片描述

三、二叉树的性质和存储结构

1)满二叉树

在这里插入图片描述

  • 满二叉树在同样深度的二叉树中结点个数最多
  • 满二叉树在同样深度的二叉树中叶子结点个数最多

2)完全二叉树

在这里插入图片描述
在这里插入图片描述

特点:

  • 1.叶子只可能分布在层次最大的两层上。
  • 2.对任一结点,如果其右子树的最大层次为i。

则其左子树的最大层次必为 i 或 i + 1。

3)完全二叉树性质

1、性质4

在这里插入图片描述

2、性质5

性质 5:如果对一棵有 ,个结点的完全二叉树(深度为 [log2n] + 1)的结点按层序编号(从第1层到第[log2n]+1层,每层从左到右),则对任一结点 i (1≤/n),有:

在这里插入图片描述

四、二叉树顺序存储结构

在这里插入图片描述

在这里插入图片描述

1)结构定义


#define MAXTSIZE 100

typedef TElemType SqBiTree[MAXSIZE]

SqBiTree bt;

2)总体代码实现

#include <iostream>
using namespace std;

#define MAXSIZE 100  // 数组的最大容量

// 二叉树节点的数据类型
typedef char TElemType;

// 顺序存储的二叉树
typedef TElemType SqBiTree[MAXSIZE];

// 初始化二叉树
void InitSqBiTree(SqBiTree bt) {
    for (int i = 0; i < MAXSIZE; ++i) {
        bt[i] = '#'; // 使用'#'表示空节点
    }
}

// 创建二叉树
void CreateSqBiTree(SqBiTree& bt, const char* str) {
    int i = 0;
    while (str[i] != '\0') {
        if (str[i] == '#') { // 如果是空节点
            bt[++bt[0]] = '#';
        }
        else {
            bt[++bt[0]] = str[i];
        }
        ++i;
    }
}

// 前序遍历
void PreOrder(SqBiTree bt, int index) {
    if (index > bt[0] || bt[index] == '#') return;
    cout << bt[index] << " ";  // 访问当前节点
    PreOrder(bt, 2 * index);   // 递归访问左子树
    PreOrder(bt, 2 * index + 1); // 递归访问右子树
}

// 中序遍历
void InOrder(SqBiTree bt, int index) {
    if (index > bt[0] || bt[index] == '#') return;
    InOrder(bt, 2 * index);    // 递归访问左子树
    cout << bt[index] << " ";  // 访问当前节点
    InOrder(bt, 2 * index + 1); // 递归访问右子树
}

// 后序遍历
void PostOrder(SqBiTree bt, int index) {
    if (index > bt[0] || bt[index] == '#') return;
    PostOrder(bt, 2 * index);  // 递归访问左子树
    PostOrder(bt, 2 * index + 1); // 递归访问右子树
    cout << bt[index] << " ";  // 访问当前节点
}

// 层次遍历
void LevelOrder(SqBiTree bt) {
    for (int i = 1; i <= bt[0]; ++i) {
        if (bt[i] != '#') {
            cout << bt[i] << " ";
        }
    }
    cout << endl;
}

int main() {
    SqBiTree bt;
    InitSqBiTree(bt);

    // 创建二叉树,例如:"AB#C##D#E##F"
    // 这里假设输入字符串中的'#'表示空节点
    const char* treeStr = "AB#C##D#E##F";
    bt[0] = 0; // 初始化根节点位置
    CreateSqBiTree(bt, treeStr);

    cout << "前序排序: ";
    LevelOrder(bt);
    cout << "中序排序: ";
    PreOrder(bt, 1);
    cout << endl;
    cout << "后序排序: ";
    InOrder(bt, 1);
    cout << endl;
    cout << "层次排序: ";
    PostOrder(bt, 1);
    cout << endl;

    return 0;
}

五、二叉树链式存储结构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1)结构定义

typedef struct BiNode {
	TElemType data;
	struct BiNode* lchild, * rchild; //左右孩子指针
}BiNode, * BiTree;

2)总体代码实现

#include <iostream>
#include <queue>
using namespace std;

// 二叉树节点的数据类型
typedef char TElemType;

// 二叉树节点定义
typedef struct BiNode {
    TElemType data;
    struct BiNode* lchild, * rchild; // 左右孩子指针
} BiNode, * BiTree;

// 创建新节点
BiNode* CreateNode(TElemType data) {
    BiNode* newNode = new BiNode;
    newNode->data = data;
    newNode->lchild = nullptr;
    newNode->rchild = nullptr;
    return newNode;
}

// 创建二叉树
BiTree CreateBiTree() {
    // 创建根节点
    BiTree A = CreateNode('A');
    BiTree B = CreateNode('B');
    BiTree C = CreateNode('C');
    BiTree D = CreateNode('D');
    BiTree E = CreateNode('E');
    BiTree F = CreateNode('F');
    BiTree G = CreateNode('G');
    BiTree H = CreateNode('H');
    BiTree I = CreateNode('I');

    // 构建二叉树
    A->lchild = B; A->rchild = C;
    B->lchild = D; B->rchild = E;
    C->lchild = F; C->rchild = G;
    D->lchild = H; D->rchild = nullptr;
    E->lchild = I; E->rchild = nullptr;
    F->lchild = nullptr; F->rchild = nullptr;
    G->lchild = nullptr; G->rchild = nullptr;
    H->lchild = nullptr; H->rchild = nullptr;
    I->lchild = nullptr; I->rchild = nullptr;

    return A;
}

// 前序遍历(根 -> 左子树 -> 右子树)
void PreOrder(BiTree T) {
    if (T == nullptr) return;
    cout << T->data << " ";  // 访问当前节点
    PreOrder(T->lchild);     // 递归访问左子树
    PreOrder(T->rchild);     // 递归访问右子树
}

// 中序遍历(左子树 -> 根 -> 右子树)
void InOrder(BiTree T) {
    if (T == nullptr) return;
    InOrder(T->lchild);      // 递归访问左子树
    cout << T->data << " ";  // 访问当前节点
    InOrder(T->rchild);      // 递归访问右子树
}

// 后序遍历(左子树 -> 右子树 -> 根)
void PostOrder(BiTree T) {
    if (T == nullptr) return;
    PostOrder(T->lchild);    // 递归访问左子树
    PostOrder(T->rchild);    // 递归访问右子树
    cout << T->data << " ";  // 访问当前节点
}

// 层次遍历(广度优先遍历)
void LevelOrder(BiTree T) {
    if (T == nullptr) return;

    queue<BiTree> q;
    q.push(T);

    while (!q.empty()) {
        BiTree p = q.front();
        q.pop();

        cout << p->data << " ";  // 访问当前节点

        if (p->lchild != nullptr) {
            q.push(p->lchild);   // 将左子节点加入队列
        }

        if (p->rchild != nullptr) {
            q.push(p->rchild);   // 将右子节点加入队列
        }
    }
    cout << endl;
}

// 递归删除二叉树
void DeleteTree(BiTree& T) {
    if (T == nullptr) return;
    DeleteTree(T->lchild);
    DeleteTree(T->rchild);
    delete T;
    T = nullptr;
}

int main() {
    // 创建二叉树
    BiTree root = CreateBiTree();

    // 输出前序遍历结果
    cout << "前序遍历: ";
    PreOrder(root);
    cout << endl;

    // 输出中序遍历结果
    cout << "中序遍历: ";
    InOrder(root);
    cout << endl;

    // 输出后序遍历结果
    cout << "后序遍历: ";
    PostOrder(root);
    cout << endl;

    // 输出层次遍历结果
    cout << "层次遍历: ";
    LevelOrder(root);

    // 清理内存
    DeleteTree(root);

    return 0;
}

六、三叉链表

在这里插入图片描述

七、遍历二叉树

1)介绍

在这里插入图片描述

在这里插入图片描述

2)先序,中序,后序遍历介绍

若规定先左后右,则只有前三种情况:

  • DLR --先(根)序遍历(中前后
  • LDR --中(根)序遍历(前中后
  • LRD --后(根)序遍历(前后中

在这里插入图片描述

注意:

  • 若二又树中各结点的值均不相同,则二又树结点的先序序列、中序序列和后序序列都是唯一的。
  • 由二叉树的先序序列和中序序列,或由二叉树的后序序列和中序序列可以确定唯一棵二叉树。

案例:

1、由先序和中序求二叉树

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2、由中序和后序求二叉树

在这里插入图片描述

3)先,中,后序递归算法实现

1、先序遍历

在这里插入图片描述

以上先序序列为:A B D C

Status PreOrderTraverse(BiTree T) {
	if (T == NULL) return OK; // 空二叉树
	else {
		visit(T); // 访问根结点
		PreOrderTraverse(T->lchild); // 递归遍历左子树
		PreOrderTraverse(T->rchild); // 递归遍历右子树
	}
}
2、中序遍历

在这里插入图片描述

Status InOrderTraverse(BiTree T) {
	if (T == NULL) return OK; // 空二叉树
	else {
		InOrderTraverse(T->lchild); // 递归遍历左子树
		visit(T); / /访问根结点;
		InOrdenTraverse(T->rchild); // 递归遍历右子树
	}
}
3、后序遍历

在这里插入图片描述

Status PostOrderTraverse(BiTree T) {
	if (T == NULL) return OK; //空二叉树
	else {
		PostOrderTraverse(F->lchild); // 递归遍历左子树
		PostOrderTraverse(T->rchild); // 递归遍历右子树
		visit(T);  // 访问根结点
	}
}
4、总结
C语言代码实现
#include <stdio.h>
#include <stdlib.h>

// 二叉树节点定义
typedef struct BiTNode {
    char data;
    struct BiTNode* lchild, * rchild;
} BiTNode, * BiTree;

// 创建一个简单的二叉树
BiTree CreateBiTree() {
    BiTree A, B, C, D, E, F, G, H, I;
    A = (BiTree)malloc(sizeof(BiTNode));
    B = (BiTree)malloc(sizeof(BiTNode));
    C = (BiTree)malloc(sizeof(BiTNode));
    D = (BiTree)malloc(sizeof(BiTNode));
    E = (BiTree)malloc(sizeof(BiTNode));
    F = (BiTree)malloc(sizeof(BiTNode));
    G = (BiTree)malloc(sizeof(BiTNode));
    H = (BiTree)malloc(sizeof(BiTNode));
    I = (BiTree)malloc(sizeof(BiTNode));

    A->data = 'A'; A->lchild = B; A->rchild = C;
    B->data = 'B'; B->lchild = D; B->rchild = E;
    C->data = 'C'; C->lchild = F; C->rchild = G;
    D->data = 'D'; D->lchild = H; D->rchild = NULL;
    E->data = 'E'; E->lchild = I; E->rchild = NULL;
    F->data = 'F'; F->lchild = NULL; F->rchild = NULL;
    G->data = 'G'; G->lchild = NULL; G->rchild = NULL;
    H->data = 'H'; H->lchild = NULL; H->rchild = NULL;
    I->data = 'I'; I->lchild = NULL; I->rchild = NULL;

    return A;
}

// 先序遍历
void PreOrderTraverse(BiTree T) {
    if (T == NULL) return;
    printf("%c ", T->data);  // 访问当前节点
    PreOrderTraverse(T->lchild);  // 递归访问左子树
    PreOrderTraverse(T->rchild);  // 递归访问右子树
}

// 中序遍历
void InOrderTraverse(BiTree T) {
    if (T == NULL) return;
    InOrderTraverse(T->lchild);  // 递归访问左子树
    printf("%c ", T->data);  // 访问当前节点
    InOrderTraverse(T->rchild);  // 递归访问右子树
}

// 后序遍历
void PostOrderTraverse(BiTree T) {
    if (T == NULL) return;
    PostOrderTraverse(T->lchild);  // 递归访问左子树
    PostOrderTraverse(T->rchild);  // 递归访问右子树
    printf("%c ", T->data);  // 访问当前节点
}

// 递归删除二叉树
void DeleteTree(BiTree T) {
    if (T == NULL) return;
    DeleteTree(T->lchild);
    DeleteTree(T->rchild);
    free(T);
}

int main() {
    BiTree root = CreateBiTree();

    printf("Preorder Traversal: ");
    PreOrderTraverse(root);
    printf("\n");

    printf("Inorder Traversal: ");
    InOrderTraverse(root);
    printf("\n");

    printf("Postorder Traversal: ");
    PostOrderTraverse(root);
    printf("\n");

    // 清理内存
    DeleteTree(root);

    return 0;
}
C++代码实现
#include <iostream>
using namespace std;

// 二叉树节点定义
typedef struct BiTNode {
    char data;
    BiTNode* lchild, * rchild;
} BiTNode, * BiTree;

// 创建一个简单的二叉树
BiTree CreateBiTree() {
    BiTree A = new BiTNode{ 'A', nullptr, nullptr };
    BiTree B = new BiTNode{ 'B', nullptr, nullptr };
    BiTree C = new BiTNode{ 'C', nullptr, nullptr };
    BiTree D = new BiTNode{ 'D', nullptr, nullptr };
    BiTree E = new BiTNode{ 'E', nullptr, nullptr };
    BiTree F = new BiTNode{ 'F', nullptr, nullptr };
    BiTree G = new BiTNode{ 'G', nullptr, nullptr };
    BiTree H = new BiTNode{ 'H', nullptr, nullptr };
    BiTree I = new BiTNode{ 'I', nullptr, nullptr };

    A->lchild = B; A->rchild = C;
    B->lchild = D; B->rchild = E;
    C->lchild = F; C->rchild = G;
    D->lchild = H; D->rchild = nullptr;
    E->lchild = I; E->rchild = nullptr;
    F->lchild = nullptr; F->rchild = nullptr;
    G->lchild = nullptr; G->rchild = nullptr;
    H->lchild = nullptr; H->rchild = nullptr;
    I->lchild = nullptr; I->rchild = nullptr;

    return A;
}

// 先序遍历
void PreOrderTraverse(BiTree T) {
    if (T == nullptr) return;
    cout << T->data << " ";  // 访问当前节点
    PreOrderTraverse(T->lchild);  // 递归访问左子树
    PreOrderTraverse(T->rchild);  // 递归访问右子树
}

// 中序遍历
void InOrderTraverse(BiTree T) {
    if (T == nullptr) return;
    InOrderTraverse(T->lchild);  // 递归访问左子树
    cout << T->data << " ";  // 访问当前节点
    InOrderTraverse(T->rchild);  // 递归访问右子树
}

// 后序遍历
void PostOrderTraverse(BiTree T) {
    if (T == nullptr) return;
    PostOrderTraverse(T->lchild);  // 递归访问左子树
    PostOrderTraverse(T->rchild);  // 递归访问右子树
    cout << T->data << " ";  // 访问当前节点
}

// 递归删除二叉树
void DeleteTree(BiTree& T) {
    if (T == nullptr) return;
    DeleteTree(T->lchild);
    DeleteTree(T->rchild);
    delete T;
    T = nullptr;
}

int main() {
    BiTree root = CreateBiTree();

    cout << "Preorder Traversal: ";
    PreOrderTraverse(root);
    cout << endl;

    cout << "Inorder Traversal: ";
    InOrderTraverse(root);
    cout << endl;

    cout << "Postorder Traversal: ";
    PostOrderTraverse(root);
    cout << endl;

    // 清理内存
    DeleteTree(root);

    return 0;
}

4)先,中,后序非递归算法实现

用栈来实现

在这里插入图片描述

1、先序排序
Status PreOrderTraverse(BiTree T) {
    BiTree p, q;
    InitStack(S);
    p = T;
    while (p || !StackEmpty(S)) {
        if (p) {
            printf("%c", p->data);  // 访问当前节点
            Push(S, p);
            p = p->lchild;  // 向左子树走
        } else {
            Pop(S, q);
            p = q->rchild;  // 转向右子树
        }
    }
    return OK;
}
2、中序排序
Status InOrderTraverse(BiTree T) {
	BiTree p;
	InitStack(S);
	p = T;
	while (p || !StackEmpty(S)) {
		if (p) {
			Push(S, p);
			p = p->lchild;
		}
		else {
			Pop(S, q);
			printf("%c", q->data);
			p = q->rchild;
		}
	}//while
	return OK;
} 
3、后序排序
Status PostOrderTraverse(BiTree T) {
    BiTree p, q, r;
    InitStack(S);
    p = T;
    r = NULL;  // 用来记录最近一次访问的节点
    while (p || !StackEmpty(S)) {
        if (p) {
            Push(S, p);
            p = p->lchild;  // 沿着左子树向下
        } else {
            GetTop(S, q);
            // 如果右子树为空或者右子树已经被访问过
            if (q->rchild == NULL || q->rchild == r) {
                Pop(S, q);
                printf("%c", q->data);  // 访问当前节点
                r = q;  // 更新最近访问的节点
                p = NULL;  // 设置p为NULL,防止下一轮循环继续处理
            } else {
                p = q->rchild;  // 转向右子树
            }
        }
    }
    return OK;
}
4、总结
C语言代码实现
#include <stdio.h>
#include <stdlib.h>

// 二叉树节点定义
typedef struct BiTNode {
    char data;
    struct BiTNode* lchild, * rchild;
} BiTNode, * BiTree;

// 栈的操作函数
#define MAXSIZE 100

typedef struct {
    BiTree data[MAXSIZE];
    int top;
} Stack;

void InitStack(Stack* S) {
    S->top = -1;
}

int StackEmpty(Stack S) {
    return S.top == -1;
}

int Push(Stack* S, BiTree e) {
    if (S->top >= MAXSIZE - 1) return 0; // 栈满
    S->data[++S->top] = e;
    return 1;
}

int Pop(Stack* S, BiTree* e) {
    if (S->top == -1) return 0; // 栈空
    *e = S->data[S->top--];
    return 1;
}

// 创建一个简单的二叉树
BiTree CreateBiTree() {
    BiTree A, B, C, D, E, F, G, H, I;
    A = (BiTree)malloc(sizeof(BiTNode));
    B = (BiTree)malloc(sizeof(BiTNode));
    C = (BiTree)malloc(sizeof(BiTNode));
    D = (BiTree)malloc(sizeof(BiTNode));
    E = (BiTree)malloc(sizeof(BiTNode));
    F = (BiTree)malloc(sizeof(BiTNode));
    G = (BiTree)malloc(sizeof(BiTNode));
    H = (BiTree)malloc(sizeof(BiTNode));
    I = (BiTree)malloc(sizeof(BiTNode));

    A->data = 'A'; A->lchild = B; A->rchild = C;
    B->data = 'B'; B->lchild = D; B->rchild = E;
    C->data = 'C'; C->lchild = F; C->rchild = G;
    D->data = 'D'; D->lchild = H; D->rchild = NULL;
    E->data = 'E'; E->lchild = I; E->rchild = NULL;
    F->data = 'F'; F->lchild = NULL; F->rchild = NULL;
    G->data = 'G'; G->lchild = NULL; G->rchild = NULL;
    H->data = 'H'; H->lchild = NULL; H->rchild = NULL;
    I->data = 'I'; I->lchild = NULL; I->rchild = NULL;

    return A;
}

// 先序遍历
void PreOrderTraverse(BiTree T) {
    if (T == NULL) return;
    Stack S;
    InitStack(&S);
    BiTree p = T;
    while (p != NULL || !StackEmpty(S)) {
        while (p != NULL) {
            printf("%c ", p->data);  // 访问当前节点
            Push(&S, p);
            p = p->lchild;  // 向左子树走
        }
        if (!StackEmpty(S)) {
            Pop(&S, &p);
            p = p->rchild;  // 转向右子树
        }
    }
    printf("\n");
}

// 中序遍历
void InOrderTraverse(BiTree T) {
    if (T == NULL) return;
    Stack S;
    InitStack(&S);
    BiTree p = T;
    while (p != NULL || !StackEmpty(S)) {
        while (p != NULL) {
            Push(&S, p);
            p = p->lchild;  // 向左子树走
        }
        if (!StackEmpty(S)) {
            Pop(&S, &p);
            printf("%c ", p->data);  // 访问当前节点
            p = p->rchild;  // 转向右子树
        }
    }
    printf("\n");
}

// 后序遍历
void PostOrderTraverse(BiTree T) {
    if (T == NULL) return;
    Stack S1, S2;
    InitStack(&S1);
    InitStack(&S2);
    BiTree p = T;
    Push(&S1, p);
    while (!StackEmpty(S1)) {
        Pop(&S1, &p);
        Push(&S2, p);
        if (p->lchild != NULL) Push(&S1, p->lchild);  // 左子树入栈
        if (p->rchild != NULL) Push(&S1, p->rchild);  // 右子树入栈
    }
    while (!StackEmpty(S2)) {
        Pop(&S2, &p);
        printf("%c ", p->data);  // 访问当前节点
    }
    printf("\n");
}

// 递归删除二叉树
void DeleteTree(BiTree T) {
    if (T == NULL) return;
    DeleteTree(T->lchild);
    DeleteTree(T->rchild);
    free(T);
}

int main() {
    BiTree root = CreateBiTree();

    printf("Preorder Traversal: ");
    PreOrderTraverse(root);

    printf("Inorder Traversal: ");
    InOrderTraverse(root);

    printf("Postorder Traversal: ");
    PostOrderTraverse(root);

    // 清理内存
    DeleteTree(root);

    return 0;
}
C++代码实现
#include <iostream>
#include <stack>

using namespace std;

// 二叉树节点定义
typedef struct BiTNode {
    char data;
    BiTNode* lchild, * rchild;
} BiTNode, * BiTree;

// 创建一个简单的二叉树
BiTree CreateBiTree() {
    // 创建根节点
    BiTree A = new BiTNode{ 'A', nullptr, nullptr };
    BiTree B = new BiTNode{ 'B', nullptr, nullptr };
    BiTree C = new BiTNode{ 'C', nullptr, nullptr };
    BiTree D = new BiTNode{ 'D', nullptr, nullptr };
    BiTree E = new BiTNode{ 'E', nullptr, nullptr };
    BiTree F = new BiTNode{ 'F', nullptr, nullptr };
    BiTree G = new BiTNode{ 'G', nullptr, nullptr };
    BiTree H = new BiTNode{ 'H', nullptr, nullptr };
    BiTree I = new BiTNode{ 'I', nullptr, nullptr };

    // 构建二叉树
    A->lchild = B; A->rchild = C;
    B->lchild = D; B->rchild = E;
    C->lchild = F; C->rchild = G;
    D->lchild = H; D->rchild = nullptr;
    E->lchild = I; E->rchild = nullptr;
    F->lchild = nullptr; F->rchild = nullptr;
    G->lchild = nullptr; G->rchild = nullptr;
    H->lchild = nullptr; H->rchild = nullptr;
    I->lchild = nullptr; I->rchild = nullptr;

    return A;
}

// 先序遍历
void PreOrderTraverse(BiTree T) {
    if (T == nullptr) return;
    stack<BiTree> s;
    BiTree p = T;
    while (p != nullptr || !s.empty()) {
        while (p != nullptr) {
            cout << p->data << " ";  // 访问当前节点
            s.push(p);
            p = p->lchild;  // 向左子树走
        }
        if (!s.empty()) {
            p = s.top();
            s.pop();
            p = p->rchild;  // 转向右子树
        }
    }
    cout << endl;
}

// 中序遍历
void InOrderTraverse(BiTree T) {
    if (T == nullptr) return;
    stack<BiTree> s;
    BiTree p = T;
    while (p != nullptr || !s.empty()) {
        while (p != nullptr) {
            s.push(p);
            p = p->lchild;  // 向左子树走
        }
        if (!s.empty()) {
            p = s.top();
            s.pop();
            cout << p->data << " ";  // 访问当前节点
            p = p->rchild;  // 转向右子树
        }
    }
    cout << endl;
}

// 后序遍历
void PostOrderTraverse(BiTree T) {
    if (T == nullptr) return;
    stack<BiTree> s1, s2;
    s1.push(T);
    while (!s1.empty()) {
        T = s1.top();
        s1.pop();
        s2.push(T);
        if (T->lchild != nullptr) s1.push(T->lchild);  // 左子树入栈
        if (T->rchild != nullptr) s1.push(T->rchild);  // 右子树入栈
    }
    while (!s2.empty()) {
        T = s2.top();
        s2.pop();
        cout << T->data << " ";  // 访问当前节点
    }
    cout << endl;
}

// 递归删除二叉树
void DeleteTree(BiTree& root) {
    if (root == nullptr) return;
    DeleteTree(root->lchild);
    DeleteTree(root->rchild);
    delete root;
    root = nullptr;
}

int main() {
    BiTree root = CreateBiTree();

    cout << "Preorder Traversal: ";
    PreOrderTraverse(root);

    cout << "Inorder Traversal: ";
    InOrderTraverse(root);

    cout << "Postorder Traversal: ";
    PostOrderTraverse(root);

    // 清理内存
    DeleteTree(root);

    return 0;
}

5)二叉树层次遍历

1、层次遍历代码

// 层次遍历
void LevelOrder(BiTree b) {
    BTNode* p;
    SqQueue qu;
    InitQueue(&qu);  // 初始化队列
    enQueue(&qu, b); // 根结点指针进入队列

    while (!QueueEmpty(qu)) { // 队不为空,则循环
        deQueue(&qu, &p);     // 出队结点p
        printf("%c ", p->data); // 访问结点p

        if (p->lchild != NULL) {
            enQueue(&qu, p->lchild); // 有左孩子时将其进队
        }

        if (p->rchild != NULL) {
            enQueue(&qu, p->rchild); // 有右孩子时将其进队
        }
    }
    printf("\n");
}

2、总体代码

C语言代码实现
#include <stdio.h>
#include <stdlib.h>

#define MaxSize 100 // 队列的最大容量

// 二叉树节点定义
typedef struct BTNode {
    char data;
    struct BTNode* lchild, * rchild;
} BTNode, * BiTree;

// 顺序循环队列类型
typedef struct {
    BTNode* data[MaxSize]; // 存放队中元素
    int front, rear;       // 队头和队尾指针
} SqQueue;

// 初始化队列
void InitQueue(SqQueue* qu) {
    qu->front = qu->rear = 0;
}

// 判断队列是否为空
int QueueEmpty(SqQueue qu) {
    return qu.front == qu.rear;
}

// 入队
int enQueue(SqQueue* qu, BTNode* e) {
    if ((qu->rear + 1) % MaxSize == qu->front) { // 队满
        return 0;
    }
    qu->data[qu->rear] = e;
    qu->rear = (qu->rear + 1) % MaxSize;
    return 1;
}

// 出队
int deQueue(SqQueue* qu, BTNode** e) {
    if (qu->front == qu->rear) { // 队空
        return 0;
    }
    *e = qu->data[qu->front];
    qu->front = (qu->front + 1) % MaxSize;
    return 1;
}

// 创建一个简单的二叉树
BiTree CreateBiTree() {
    BiTree A = (BiTree)malloc(sizeof(BTNode));
    BiTree B = (BiTree)malloc(sizeof(BTNode));
    BiTree C = (BiTree)malloc(sizeof(BTNode));
    BiTree D = (BiTree)malloc(sizeof(BTNode));
    BiTree E = (BiTree)malloc(sizeof(BTNode));
    BiTree F = (BiTree)malloc(sizeof(BTNode));
    BiTree G = (BiTree)malloc(sizeof(BTNode));
    BiTree H = (BiTree)malloc(sizeof(BTNode));
    BiTree I = (BiTree)malloc(sizeof(BTNode));

    A->data = 'A'; A->lchild = B; A->rchild = C;
    B->data = 'B'; B->lchild = D; B->rchild = E;
    C->data = 'C'; C->lchild = F; C->rchild = G;
    D->data = 'D'; D->lchild = H; D->rchild = NULL;
    E->data = 'E'; E->lchild = I; E->rchild = NULL;
    F->data = 'F'; F->lchild = NULL; F->rchild = NULL;
    G->data = 'G'; G->lchild = NULL; G->rchild = NULL;
    H->data = 'H'; H->lchild = NULL; H->rchild = NULL;
    I->data = 'I'; I->lchild = NULL; I->rchild = NULL;

    return A;
}

// 层次遍历
void LevelOrder(BiTree b) {
    BTNode* p;
    SqQueue qu;
    InitQueue(&qu);  // 初始化队列
    enQueue(&qu, b); // 根结点指针进入队列

    while (!QueueEmpty(qu)) { // 队不为空,则循环
        deQueue(&qu, &p);     // 出队结点p
        printf("%c ", p->data); // 访问结点p

        if (p->lchild != NULL) {
            enQueue(&qu, p->lchild); // 有左孩子时将其进队
        }

        if (p->rchild != NULL) {
            enQueue(&qu, p->rchild); // 有右孩子时将其进队
        }
    }
    printf("\n");
}

// 递归删除二叉树
void DeleteTree(BiTree T) {
    if (T == NULL) return;
    DeleteTree(T->lchild);
    DeleteTree(T->rchild);
    free(T);
}

int main() {
    BiTree root = CreateBiTree();

    printf("Level Order Traversal: ");
    LevelOrder(root);

    // 清理内存
    DeleteTree(root);

    return 0;
}
C++代码实现
#include <iostream>
#include <queue>
using namespace std;

// 二叉树节点定义
typedef struct BTNode {
    char data;
    BTNode *lchild, *rchild;
} BTNode, *BiTree;

// 创建一个简单的二叉树
BiTree CreateBiTree() {
    BiTree A = new BTNode{ 'A', nullptr, nullptr };
    BiTree B = new BTNode{ 'B', nullptr, nullptr };
    BiTree C = new BTNode{ 'C', nullptr, nullptr };
    BiTree D = new BTNode{ 'D', nullptr, nullptr };
    BiTree E = new BTNode{ 'E', nullptr, nullptr };
    BiTree F = new BTNode{ 'F', nullptr, nullptr };
    BiTree G = new BTNode{ 'G', nullptr, nullptr };
    BiTree H = new BTNode{ 'H', nullptr, nullptr };
    BiTree I = new BTNode{ 'I', nullptr, nullptr };

    A->lchild = B; A->rchild = C;
    B->lchild = D; B->rchild = E;
    C->lchild = F; C->rchild = G;
    D->lchild = H; D->rchild = nullptr;
    E->lchild = I; E->rchild = nullptr;
    F->lchild = nullptr; F->rchild = nullptr;
    G->lchild = nullptr; G->rchild = nullptr;
    H->lchild = nullptr; H->rchild = nullptr;
    I->lchild = nullptr; I->rchild = nullptr;

    return A;
}

// 层次遍历
void LevelOrder(BiTree b) {
    if (b == nullptr) return;

    // 使用队列进行层次遍历
    queue<BiTree> q;
    q.push(b);

    while (!q.empty()) {
        BiTree p = q.front();
        q.pop();

        cout << p->data << " ";  // 访问当前节点

        // 将左子节点加入队列
        if (p->lchild != nullptr) {
            q.push(p->lchild);
        }

        // 将右子节点加入队列
        if (p->rchild != nullptr) {
            q.push(p->rchild);
        }
    }
    cout << endl;
}

// 递归删除二叉树
void DeleteTree(BiTree &T) {
    if (T == nullptr) return;
    DeleteTree(T->lchild);
    DeleteTree(T->rchild);
    delete T;
    T = nullptr;
}

int main() {
    BiTree root = CreateBiTree();

    cout << "Level Order Traversal: ";
    LevelOrder(root);  // 层次遍历

    // 清理内存
    DeleteTree(root);

    return 0;
}

八、二叉树的创建

1)先序创建二叉树

Status CreateBiTree(BiTree &T) {
	scanf(&ch);//cin>>ch;
	if(ch== “#”) T= NULL
	else {if (!(T =(BiTNode *)malloc(sizeof(BiTNode))))
		exit(OVERFLOW); //T=new BiTNode;
	T->data=ch; //生成根结点
	CreateBiTree(T->lchild); //构造左子树
	CreateBiTree(T->rchild);//构造右子树
	return OK;
}// CreateBiTree

2)总体代码实现

在这里插入图片描述

#include <iostream>
#include <queue>
using namespace std;

// 二叉树节点的数据类型
typedef char TElemType;

typedef int Status;	//Status是函数的类型,其值是函数结果状态代码,如OK等

// 二叉树节点定义
typedef struct BiTNode {
    TElemType data;
    struct BiTNode* lchild, * rchild; // 左右孩子指针
} BiTNode, * BiTree;

// 状态码定义
#define OK 1
#define ERROR 0
#define OVERFLOW -2

// 创建新节点
Status CreateBiTree(BiTree& T) {
    TElemType ch;
    cin >> ch;  // 读取一个字符

    if (ch == '#') {
        T = NULL;  // 如果是 '#',表示空节点
    }
    else {
        if (!(T = (BiTNode*)malloc(sizeof(BiTNode)))) {
            exit(OVERFLOW);  // 内存分配失败
        }
        T->data = ch;  // 生成根节点
        CreateBiTree(T->lchild);  // 构造左子树
        CreateBiTree(T->rchild);  // 构造右子树
    }
    return OK;
}

// 前序遍历(根 -> 左子树 -> 右子树)
void PreOrder(BiTree T) {
    if (T == NULL) return;
    cout << T->data << " ";  // 访问当前节点
    PreOrder(T->lchild);     // 递归访问左子树
    PreOrder(T->rchild);     // 递归访问右子树
}

// 中序遍历(左子树 -> 根 -> 右子树)
void InOrder(BiTree T) {
    if (T == NULL) return;
    InOrder(T->lchild);      // 递归访问左子树
    cout << T->data << " ";  // 访问当前节点
    InOrder(T->rchild);      // 递归访问右子树
}

// 后序遍历(左子树 -> 右子树 -> 根)
void PostOrder(BiTree T) {
    if (T == NULL) return;
    PostOrder(T->lchild);    // 递归访问左子树
    PostOrder(T->rchild);    // 递归访问右子树
    cout << T->data << " ";  // 访问当前节点
}

// 层次遍历(广度优先遍历)
void LevelOrder(BiTree T) {
    if (T == NULL) return;

    queue<BiTree> q;
    q.push(T);

    while (!q.empty()) {
        BiTree p = q.front();
        q.pop();

        cout << p->data << " ";  // 访问当前节点

        if (p->lchild != NULL) {
            q.push(p->lchild);   // 将左子节点加入队列
        }

        if (p->rchild != NULL) {
            q.push(p->rchild);   // 将右子节点加入队列
        }
    }
    cout << endl;
}

// 递归删除二叉树
void DeleteTree(BiTree& T) {
    if (T == NULL) return;
    DeleteTree(T->lchild);
    DeleteTree(T->rchild);
    free(T);
    T = NULL;
}

int main() {
    BiTree root = NULL;

    // 创建二叉树
    cout << "请输入先序遍历序列(使用 '#' 表示空节点): ";
    CreateBiTree(root);

    // 输出前序遍历结果
    cout << "前序遍历: ";
    PreOrder(root);
    cout << endl;

    // 输出中序遍历结果
    cout << "中序遍历: ";
    InOrder(root);
    cout << endl;

    // 输出后序遍历结果
    cout << "后序遍历: ";
    PostOrder(root);
    cout << endl;

    // 输出层次遍历结果
    cout << "层次遍历: ";
    LevelOrder(root);

    // 清理内存
    DeleteTree(root);

    return 0;
}

在这里插入图片描述

九、复制二叉树

在这里插入图片描述

int Copy(BiTree T, BiTree& NewT) {
	if (T == NULL) { //如果是空树返回0
		NewT = NULL;
		return O;
	}
	else {
		NewT = new BiTNode;
		NewT->data = T->data;
		Copy(T->IChild, NewT->lchild);
		Copy(T->rChild, NewT->rchild);
	}
}

十、计算二叉树深度

int Depth(BiTree T) {
	if (T == NULL) {
		return 0;//如果是空树返回0
	}
	else {
		m = Depth(T->IChild);
		n = Depth(T->rChild);
		if (m > n) return(m + 1);
		else return(n + 1);
	}
}

十一、计算二叉树结点总数

在这里插入图片描述

int NodeCount(BiTree T) {
	if (T == NULL) return 0;
	else
		return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
}

十二、求叶子结点数

在这里插入图片描述

int LeadCount(BiTree T) {
	if (T == NULL)
		//如果是空树返回0
		return 0;
	
	if (T->Ichild == NULL && T->rchild == NULL)//如果是叶子结点返回1
		return 1;
	else
		return LeafCount(T->lchild) + LeafCount(T->rchild);
}

十三、线序二叉树

1)介绍

提出的问题:

  • 如何寻找特定遍历序列中二又树结点的前驱和后继???

解决的方法:

  1. 通过遍历寻找–费时间。
  2. 再增设前驱、后继指针域–增加了存储负担。
  3. 利用二叉链表中的空指针域。

在这里插入图片描述

利用二叉链表中的空指针域:

如果某个结点的左孩子为空,则将空的左孩子指针域改为指向其前驱,如果某结点的右孩子为空,则将空的右孩子指针域改为指向其后继

  • ——这种改变指向的指针称为 “线索
  • 加上了线索的二又树称为线索二叉树(Threaded Binary Tree)

对二叉树按某种遍历次序使其变为线索二叉树的过程叫线索化

2)线索化过程

在这里插入图片描述

为区分lrchid和rchild指针到底是指向孩子的指针,还是指向前驱或者后继的指针,对二叉链表中每个结点增设

两个标志域 ltag 和 rtag ,并约定:

ltag = 0    lchild 指向该结点的左孩子
rtag = 0    rchild 指向该结点的右孩子

ltag = 1    lchild 指向该结点的前驱
rtag = 1	rchild 指向该结点的后继

在这里插入图片描述

typedef struct BiThrNode{
	int data;
	int ltag, rtag;
	struct BiThrNode *lchild, rchild;
} BiThrNode, *BiThrTree ;

3)先序线索二叉树

在这里插入图片描述

4)中序线索二叉树

在这里插入图片描述

5)后序线索二叉树

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/942999.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MVC架构模式

分析AccountTransferServlet类都负责了什么&#xff1f; 数据接收核心的业务处理数据库表中数据的crud操作负责了页面的数据展示做了很多 在不使用MVC架构模式的前提下&#xff0c;完成银行账户转账的缺点&#xff1a; 代码的复用性太差。因为没有进行职能分工&#xff0c;没有…

打破视障壁垒,百度文心快码无障碍版本助力视障IT从业者就业无“碍”

有AI无碍 钟科&#xff1a;被黑暗卡住的开发梦 提起视障群体的就业&#xff0c;绝大部分人可能只能想到盲人按摩。但你知道吗&#xff1f;视障人士也能写代码。 钟科&#xff0c;一个曾经“被黑暗困住”的人&#xff0c;他的世界&#xff0c;因为一场突如其来的疾病&#xff0c…

【RAG实战】语言模型基础

语言模型赋予了计算机理解和生成人类语言的能力。它结合了统计学原理和深度神经网络技术&#xff0c;通过对大量的样本数据进行复杂的概率分布分析来学习语言结构的内在模式和相关性。具体地&#xff0c;语言模型可根据上下文中已出现的词序列&#xff0c;使用概率推断来预测接…

48页PPT|2024智慧仓储解决方案解读

本文概述了智慧物流仓储建设方案的行业洞察、业务蓝图及建设方案。首先&#xff0c;从政策层面分析了2012年至2020年间国家发布的促进仓储业、物流业转型升级的政策&#xff0c;这些政策强调了自动化、标准化、信息化水平的提升&#xff0c;以及智能化立体仓库的建设&#xff0…

Matlab环形柱状图

数据准备&#xff1a; 名称 数值 Aa 21 Bb 23 Cc 35 Dd 47 保存为Excel文件后&#xff1a; % Load data from Excel file filename data.xlsx; % Ensure the file is in the current folder or provide full path dataTable readtable(filena…

flask后端开发(3):html模板渲染

目录 渲染模板html模板获取路由参数 gitcode地址&#xff1a; https://gitcode.com/qq_43920838/flask_project.git 渲染模板 这样就能够通过html文件来渲染前端&#xff0c;而不是通过return了 html模板获取路由参数

15 break和continue

while True: content input("请输入你要喷的内容") print("发送给下路",content) #上述的程序如果没有外力干扰&#xff1a;程序会一直进行输入下去 #break:就能让当前这个循环立即进行停止 while True: content input("请输入…

Python9-作业2

记录python学习&#xff0c;直到学会基本的爬虫&#xff0c;使用python搭建接口自动化测试就算学会了&#xff0c;在进阶webui自动化&#xff0c;app自动化 python基础8-灵活运用顺序、选择、循环结构 作业2九九乘法表三种方式打印九九乘法表使用两个嵌套循环使用列表推导式和…

微信小程序 不同角色进入不同页面、呈现不同底部导航栏

遇到这个需求之前一直使用的小程序默认底部导航栏&#xff0c;且小程序默认入口页面为pages/index/index&#xff0c;要使不同角色呈现不同底部导航栏&#xff0c;必须要在不同页面引用不同的自定义导航栏。本篇将结合分包&#xff08;subPackages&#xff09;展开以下三步叙述…

表达式语句、复合语句和空语句

欢迎拜访&#xff1a;雾里看山-CSDN博客 本篇主题&#xff1a;表达式语句、复合语句和空语句 发布时间&#xff1a;2024.12.26 隶属专栏&#xff1a;C语言 目录 1. 表达式语句定义作用常见类型赋值语句函数调用语句 2. 复合语句定义作用变量作用域 3. 空语句定义作用 1. 表达式…

Linux arm 编译安装glibc-2.29

重要的话说三遍&#xff1a; &#xff01;&#xff01;&#xff01;&#xff01;&#xff01;不要轻易自己去安装glibc&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; &#xff01;&#xff01;&#xff01;&#xff01;&#xff01;不要轻易自己去安装glibc&a…

20241225在ubuntu22.04.5下使用smartmontools命令查看ssd的寿命

20241225在ubuntu22.04.5下使用smartmontools命令查看ssd的寿命 2024/12/25 15:10 rootrootrootroot-ThinkBook-16-G5-IRH:~$ sudo apt install smartmontools rootrootrootroot-ThinkBook-16-G5-IRH:~$ sudo fdisk -l Disk /dev/nvme0n1: 3.73 TiB, 4096805658624 bytes, 800…

大数据学习之Redis 缓存数据库二,Scala分布式语言一

一.Redis 缓存数据库二 26.Redis数据安全_AOF持久化机制 27.Redis数据安全_企业中该如何选择持久化机制 28.Redis集群_主从复制概念 29.Redis集群_主从复制搭建 30.Redis集群_主从复制原理剖析 31.Redis集群_哨兵监控概述 32.Redis集群_配置哨兵监控 33.Redis集群_哨兵监控原理…

Datawhale AI 冬令营学习笔记-零编程基础制作井字棋小游戏

井字棋小游戏是通过豆包MarsCode实现的&#xff0c;没有改动任何的代码&#xff0c;全部是通过对话让AI进行优化和改进。 开始进入正题&#xff1a;进入豆包MarsCode在线IDE&#xff0c;直接点击上方蓝字&#xff0c;或复制链接打开: 豆包 MarsCode - 编程助手。 IDE界面&…

vscode+编程AI配置、使用说明

文章目录 [toc]1、概述2、github copilot2.1 配置2.2 使用文档2.3 使用说明 3、文心快码&#xff08;Baidu Comate&#xff09;3.1 配置3.2 使用文档3.3 使用说明 4、豆包&#xff08;MarsCode&#xff09;4.1 配置4.2 使用文档4.3 使用说明 5、通义灵码&#xff08;TONGYI Lin…

Redis数据结构和内部编码以及单线程架构

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 Redis数据结构和内部编码以及单线程架构 收录于专栏[redis] 本专栏旨在分享学习Redis的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 …

虚拟机Hyper-V,安装网络宝塔Docker

我下载的是centos-min大小1G&#xff0c;安装后没网络&#xff0c; 关闭防火墙&#xff0c;网络&#xff0c;修改onBootyes,这里需要看下network-Scripts下有什么文件。 然后就可以访问网络了 虚拟机的设置也是默认就好 网络需要设置允许共享-重要 urlhttps://download.bt.cn/i…

红魔电竞PadPro平板解BL+ROOT权限-KernelSU+LSPosed框架支持

红魔Padpro设备目前官方未开放解锁BL&#xff0c;也阉割了很多解锁BL指令&#xff0c;造成大家都不能自主玩机。此规则从红魔8开始&#xff0c;就一直延续下来&#xff0c;后续的机型大概率也是一样的情况。好在依旧有开发者进行适配研究&#xff0c;目前红魔PadPro平板&#x…

Linux-----进程处理(文件IO资源使用)

下面代码是通过父进程和子进程对同一个文件IO资源进行操作&#xff0c;父进程和子进程都对这个进程进行写入操作&#xff0c;我们都知道这两个进程实际上是并发的&#xff0c;所以需要一个同步机制来去操作同一个资源&#xff08;后面再深入去说明同步的api&#xff0c;这里使用…

EdgeX Core Service 核心服务之 Core Command 命令

EdgeX Core Service 核心服务之 Core Command 命令 一、概述 Core-command(通常称为命令和控制微服务)可以代表以下角色向设备和传感器发出命令或动作: EdgeX Foundry中的其他微服务(例如,本地边缘分析或规则引擎微服务)EdgeX Foundry与同一系统上可能存在的其他应用程序…