数据结构--树与二叉树

目录

1 . 二叉树的存储结构

顺序存储结构

链式存储结构

2 . 二叉树的遍历(递归算法)

先序遍历(递归算法)

中序遍历(递归算法)

后序遍历(递归算法)

层次遍历

计算树的深度 

完整代码 

3 . 二叉树的遍历(非递归算法)

先序遍历(非递归算法)

中序遍历(非递归算法)

后序遍历(非递归算法)

完整代码

4 . 线索二叉树

4-1 概述

4-2 中序线索二叉树

4-3 先序线索二叉树

4-4 后序线索二叉树


​​​​​​​

1 . 二叉树的存储结构

  • 顺序存储结构

#define MaxSize 100

typedef int ElemType;
typedef struct TreeNode {
    ElemType value;//结点中的数据元素
    bool isEmpty;//结点是否为空
};
TreeNode t[MaxSize];//定义一个长度为MaxSize的数组 t 来存储各个结点
  • 链式存储结构

typedef char ElemType;
typedef struct BiTNode {
    ElemType data;//数据域
    struct BiTNode *lchild, *rchild; //左 右孩子指针
//    struct BiTNode *parent;//父指针
} BiTNode, *BiTree;

2 . 二叉树的遍历(递归算法)

  • 先序遍历(递归算法)

//先序遍历
void PreOrder(BiTree T) {
    if(T) {
        visit(T);
        PreOrder(T->lchild);
        PreOrder(T->rchild);
    }
}
  • 中序遍历(递归算法)

//中序遍历
void InOrder(BiTree T) {
    if(T) {
        InOrder(T->lchild);
        visit(T);
        InOrder(T->rchild);
    }
}
  • 后序遍历(递归算法)

//后序遍历
void PostOrder(BiTree T) {
    if(T) {
        PostOrder(T->lchild);
        PostOrder(T->rchild);
        visit(T);
    }
}
  • 层次遍历

//二叉树的层次遍历
//算法思想
//1. 初始化一个辅助队列
//2.根结点入队
//3.若队列非空 则队头结点出队 访问该结点 并将其左右孩子插入队尾(如果有的话)
void LevelOrder(BiTree T) {
    LinkQueue Q;
    InitQueue(Q);//初始化辅助队列
    BiTree p;
    EnQueue(Q, T);//根结点入队
    while(!QueueEmpty(Q)) { //队列不空则循环
        DeQueue(Q, p); //队头结点出队
        visit(p);//访问出队结点
        if(p->lchild) { //左孩子不空则入队
            EnQueue(Q, p->lchild);
        }
        if(p->rchild) { //右孩子不空则入队
            EnQueue(Q, p->rchild);
        }
    }
}
  • 计算树的深度 

//计算树的深度
int treeDepth(BiTree T) {
    if(TreeEmpty(T)) { //空树
        return 0;
    }
//    后序遍历
    int l = treeDepth(T->lchild);//左子树深度
    int r = treeDepth(T->rchild);//右子树深度
    return l > r ? l + 1 : r + 1;
}
  • 完整代码 

#include <iostream>

using namespace std;
//二叉树的链式存储

typedef char ElemType;
typedef struct BiTNode {
    ElemType data;//数据域
    struct BiTNode *lchild, *rchild; //左 右孩子指针
//    struct BiTNode *parent;//父指针
} BiTNode, *BiTree;


//链式队列 不带头结点
typedef struct LinkNode { //链式队列结点
    BiTNode *data;
    struct LinkNode *next;
} LinkNode;
typedef struct { //链式队列
    LinkNode *front, *rear; //链式队列的队头和队尾指针
} LinkQueue;
bool InitQueue(LinkQueue &Q);
bool QueueEmpty(LinkQueue Q);
bool EnQueue(LinkQueue &Q, BiTNode *x);
bool DeQueue(LinkQueue &Q, BiTNode *&x);

//二叉树初始化
bool InitBiTree(BiTree &T) {
    ElemType value;
    cin >> value;
    if(value == '#') {
        T = NULL;
    } else {
        T = (BiTNode *)malloc(sizeof(BiTNode));
        if(!T) { //空间申请失败
            return false;
        }
        T->data = value;
        InitBiTree(T->lchild);
        InitBiTree(T->rchild);
    }
}
//判断是否为空
bool TreeEmpty(BiTree T) {
    if(!T) { //空树
        return true;
    } else {
        return false;
    }
}
//二叉树的遍历
//访问一个结点 打印字符
void visit(BiTNode *p) {
    cout << p->data << " ";
}
//先序遍历
void PreOrder(BiTree T) {
    if(T) {
        visit(T);
        PreOrder(T->lchild);
        PreOrder(T->rchild);
    }
}
//中序遍历
void InOrder(BiTree T) {
    if(T) {
        InOrder(T->lchild);
        visit(T);
        InOrder(T->rchild);
    }
}
//后序遍历
void PostOrder(BiTree T) {
    if(T) {
        PostOrder(T->lchild);
        PostOrder(T->rchild);
        visit(T);
    }
}
//计算树的深度
int treeDepth(BiTree T) {
    if(TreeEmpty(T)) { //空树
        return 0;
    }
//    后序遍历
    int l = treeDepth(T->lchild);//左子树深度
    int r = treeDepth(T->rchild);//右子树深度
    return l > r ? l + 1 : r + 1;
}
//二叉树的层序遍历
//算法思想
//1. 初始化一个辅助队列
//2.根结点入队
//3.若队列非空 则队头结点出队 访问该结点 并将其左右孩子插入队尾(如果有的话)
void LevelOrder(BiTree T) {
    LinkQueue Q;
    InitQueue(Q);//初始化辅助队列
    BiTree p;
    EnQueue(Q, T);//根结点入队
    while(!QueueEmpty(Q)) { //队列不空则循环
        DeQueue(Q, p); //队头结点出队
        visit(p);//访问出队结点
        if(p->lchild) { //左孩子不空则入队
            EnQueue(Q, p->lchild);
        }
        if(p->rchild) { //右孩子不空则入队
            EnQueue(Q, p->rchild);
        }
    }
}


//队列初始化
bool InitQueue(LinkQueue &Q) {
    Q.front = Q.rear = NULL; //初始为空
    return true;
}
//判断队列为空
bool QueueEmpty(LinkQueue Q) {
    if(Q.front == NULL) {
        return true;
    } else {
        return false;
    }
}
//入队
bool EnQueue(LinkQueue &Q, BiTNode *x) {
    LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
    if(!s) { //空间申请失败
        return false;
    }
    //创建新结点插入队尾
    s->data = x;
    s->next = NULL;
    if(QueueEmpty(Q)) {
        Q.front = Q.rear = s;
    } else {
        Q.rear->next = s;
        Q.rear = s;
    }
    return true;
}
//出队
bool DeQueue(LinkQueue &Q, BiTNode *&x) {
    if(QueueEmpty(Q)) { //空队
        return false;
    }
    LinkNode *p = Q.front;
    x = p->data;
    if(Q.rear == p) { //队列最后一个元素
        Q.front = Q.rear = NULL;
    } else {
        Q.front = p->next;
    }
    free(p);
    return true;
}

//由遍历序列构造二叉树
//1.前序+中序
//2.后序+中序
//3.层序+中序
void test() {
    BiTree T;
    InitBiTree(T);//ABC##DE##F##G##
    cout << "treeDepth(T):" << treeDepth(T) << endl;//4
    cout << "PreOrder" << endl;
    PreOrder(T);//A B C D E F G
    cout << endl;
    cout << "InOrder" << endl;
    InOrder(T);//C B E D F A G
    cout << endl;
    cout << "PostOrder" << endl;
    PostOrder(T);//C E F D B G A
    cout << endl;
    cout << "LevelOrder" << endl;
    LevelOrder(T);//A B G C D E F
    cout << endl;
}
int main() {
    test();
    return 0;
}

代码运行结果: 

3 . 二叉树的遍历(非递归算法)

  • 先序遍历(非递归算法)

//先序遍历
void PreOrder(BiTree T) {
    LiStack S;
    InitStack(S);
    BiTree p = T;//遍历指针
    while(p || !StackEmpty(S)) {
        if(p) {//一路向左
            visit(p);
            Push(S, p);//当前节点入栈
            p = p->lchild;//左孩子不为空一直向左走
        } else {//出栈,并转向该节点的右孩子
            Pop(S, p);//栈顶结点出栈
            p = p->rchild;//向右子树走,
        }
    }
}
  • 中序遍历(非递归算法)

//中序遍历
void InOrder(BiTree T) {
    LiStack S;
    InitStack(S);
    BiTree p = T;//遍历指针
    while(p || !StackEmpty(S)) {
        if(p) {//一路向左
            Push(S, p);//当前节点入栈
            p = p->lchild;//左孩子不为空一直向左走
        } else {//出栈,并转向该节点的右孩子
            Pop(S, p);//栈顶结点出栈,访问
            visit(p);
            p = p->rchild;//向右子树走,
        }
    }
}
  • 后序遍历(非递归算法)

//后序遍历
void PostOrder(BiTree T) {
    LiStack S;
    InitStack(S);
    BiTree p = T;
    BiTNode *r = NULL;//辅助指针,指向最近访问的节点
    while(p || !StackEmpty(S)) {
        if(p) {//走到最左边
            Push(S, p);
            p = p->lchild;
        } else {//走到最右边
            GetTop(S, p);//读栈顶元素(非出栈)
            if(p->rchild && p->rchild != r) {//若右子树存在且未被访问过
                p = p->rchild;//转向右
                Push(S, p);//压入栈
                p = p->lchild;//再走到最左
            } else {//否则弹出栈顶元素并访问
                Pop(S, p);
                visit(p);
                r = p;//记录最近访问过的节点
                p = NULL;//节点访问完后重置p指针
            }
        }
    }
}
  • 完整代码

#include<iostream>

using namespace std;

typedef char ElemType;
typedef struct BiTNode {
    ElemType data;//数据域
    struct BiTNode *lchild, *rchild;//左右孩子指针
} BiTNode, *BiTree;

typedef struct LinkNode {
    BiTNode *data;
    struct LinkNode *next;
} *LiStack, LinkNode;

//链栈初始化
bool InitStack(LiStack &S) {
    S = (LiStack)malloc(sizeof(LinkNode));
    if (!S) {
        return false;
    }
    S->next = NULL;
    return true;
}
//链栈判空
bool StackEmpty(LiStack S) {
    if (!S->next) {
        return true;
    }
    return false;
}
//压栈
bool Push(LiStack &S, BiTNode *x) {
    LinkNode *p;
    p = (LinkNode *)malloc(sizeof(LinkNode));
    if (!p) {
        return false;
    }
    p->data = x;
    p->next = S->next;
    S->next = p;
    return true;
}
//弹栈
bool Pop(LiStack &S, BiTNode *&x) {
    if (StackEmpty(S)) {
        return false;
    }
    LinkNode *p = S->next;
    S->next = p->next;
    x = p->data;
    free(p);
    return true;
}
//获得栈顶元素
bool GetTop(LiStack S, BiTNode *&x) {
    if (StackEmpty(S)) {
        return false;
    }
    x = S->next->data;
    return true;
}
//初始化二叉树
bool InitBiTree(BiTree &T) {
    ElemType value;
    cin >> value;
    if(value == '#') {
        T = NULL;
    } else {
        T = (BiTNode *)malloc(sizeof(BiTNode));
        T->data = value;
        InitBiTree(T->lchild);
        InitBiTree(T->rchild);
    }
}
//打印一个字符
void visit(BiTNode *p) {
    cout << p->data << " ";
}
//先序遍历
void PreOrder(BiTree T) {
    LiStack S;
    InitStack(S);
    BiTree p = T;//遍历指针
    while(p || !StackEmpty(S)) {
        if(p) {//一路向左
            visit(p);
            Push(S, p);//当前节点入栈
            p = p->lchild;//左孩子不为空一直向左走
        } else {//出栈,并转向该节点的右孩子
            Pop(S, p);//栈顶结点出栈
            p = p->rchild;//向右子树走,
        }
    }
}
//中序遍历
void InOrder(BiTree T) {
    LiStack S;
    InitStack(S);
    BiTree p = T;//遍历指针
    while(p || !StackEmpty(S)) {
        if(p) {//一路向左
            Push(S, p);//当前节点入栈
            p = p->lchild;//左孩子不为空一直向左走
        } else {//出栈,并转向该节点的右孩子
            Pop(S, p);//栈顶结点出栈,访问
            visit(p);
            p = p->rchild;//向右子树走,
        }
    }
}
//后序遍历
void PostOrder(BiTree T) {
    LiStack S;
    InitStack(S);
    BiTree p = T;
    BiTNode *r = NULL;//辅助指针,指向最近访问的节点
    while(p || !StackEmpty(S)) {
        if(p) {//走到最左边
            Push(S, p);
            p = p->lchild;
        } else {//走到最右边
            GetTop(S, p);//读栈顶元素(非出栈)
            if(p->rchild && p->rchild != r) {//若右子树存在且未被访问过
                p = p->rchild;//转向右
                Push(S, p);//压入栈
                p = p->lchild;//再走到最左
            } else {//否则弹出栈顶元素并访问
                Pop(S, p);
                visit(p);
                r = p;//记录最近访问过的节点
                p = NULL;//节点访问完后重置p指针
            }
        }
    }
}
void test() {
    BiTree T;
    InitBiTree(T);//ABC##DE##F##G##
    cout << "PreOrder" << endl;
    PreOrder(T);//A B C D E F G
    cout << endl;
    cout << "InOrder" << endl;
    InOrder(T);//C B E D F A G
    cout << endl;
    cout << "PostOrder" << endl;
    PostOrder(T);//C E F D B G A
    cout << endl;
}
int main() {
    test();
    return 0;
}

代码运行结果: 

4 . 线索二叉树

4-1 概述

中序线索二叉树

先序线索二叉树

后序线索二叉树

找前驱

找后继

4-2 中序线索二叉树

#include <iostream>

using namespace std;

typedef char ElemType;
typedef struct ThreadNode { //线索二叉树结点
    ElemType data;
    struct ThreadNode *lchild, *rchild;
    int ltag, rtag; //左右线索标志
//    前驱线索(由左孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
//    后继线索(由右孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
} ThreadNode, *ThreadTree;
//辅助全局变量 pre 用于查找当前访问结点的前驱
ThreadNode *pre = NULL; //指向当前访问结点的前驱结点
//二叉树初始化
bool InitThreadTree(ThreadTree &T) {
    ElemType value;
    cin >> value;
    if(value == '#') {
        T = NULL;
    } else {
        T = (ThreadTree)malloc(sizeof(ThreadNode));
        if(!T) { //空间申请失败
            return false;
        }
        T->data = value;
        T->ltag = 0;
        T->rtag = 0;
        InitThreadTree(T->lchild);
        InitThreadTree(T->rchild);
    }
    return true;
}
//二叉树的遍历
void visit(ThreadNode *q) {
    if(!q->lchild) { //左子树为空 建立前驱线索
        q->lchild = pre;
        q->ltag = 1;
    }
    if(pre != NULL && pre->rchild == NULL) {
        pre->rchild = q; //建立前驱结点的后继线索
        pre->rtag = 1;
    }
    pre = q;
}
//中序遍历二叉树 一边遍历一边线索化
void InThread(ThreadTree T) {
    if(T) {
        InThread(T->lchild);//中序遍历左子树
        visit(T);//访问根结点
        InThread(T->rchild);//中序遍历右子树
    }
}
//中序线索化二叉树 T
void CreateInThread(ThreadTree T) {
    pre = NULL;// pre 初始为NULL
    if(T) {
        InThread(T);
        if(pre->rchild == NULL) {
            pre->rtag = 1;    //处理遍历的最后一个结点
        }
    }
}
//中序线索二叉树的遍历
//求中序线索二叉树中中序序列下的第一个结点
ThreadNode *FirstNode(ThreadNode *p) {
    while (p->ltag == 0) {
        p = p->lchild;    //最左下结点(不一定是叶节点)
    }
    return p;
}
//求中序线索二叉树中结点 p 在中序序列下的后继
ThreadNode *NextNode(ThreadNode *p) {
    if(p->rtag == 0) {
        return FirstNode(p->rchild);
    } else {//rtag == 1 直接返回后继线索
        return p->rchild;
    }
}
//不含头结点的中序线索二叉树的中序遍历算法
void Inorder(ThreadNode *T) {
    for (ThreadNode *p = FirstNode(T); p != NULL; p = NextNode(p)) {
        cout << p->data << " ";
    }
    cout << endl;
}
//求中序线索二叉树中中序序列下的最后一个结点
ThreadNode *LastNode(ThreadNode *p) {
    //循环找到最右下节点(不一定是叶节点)
    while(p->rtag == 0) {
        p = p->rchild;
    }
    return p;
}
//求中序线索二叉树中结点 p 在中序序列下的前驱
ThreadNode *PreNode(ThreadNode *p) {
    //左子树中最右下节点
    if(p->ltag == 0) {
        return LastNode(p->lchild);
    }
    return p->lchild;// ltag == 1直接返回前驱线索
}
//不含头结点的中序线索二叉树的 逆序 中序遍历算法
void RevInorder(ThreadTree T) {
    for(ThreadNode *p = LastNode(T); p != NULL; p = PreNode(p)) {
        cout << p->data << " ";
    }
    cout << endl;
}

void test() {
    ThreadTree T;
    InitThreadTree(T);//ABC##DE##F##G##
    CreateInThread(T);
    cout << "InOrder" << endl;
    Inorder(T);//C B E D F A G
    cout << "RevInorder" << endl;
    RevInorder(T);//G A F D E B C
}
int main() {
    test();
    return 0;
}

代码运行结结果: 

4-3 先序线索二叉树

#include <iostream>

using namespace std;

typedef char ElemType;
typedef struct ThreadNode { //线索二叉树结点
    ElemType data;
    struct ThreadNode *lchild, *rchild;
    int ltag, rtag; //左右线索标志
    //    前驱线索(由左孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
    //    后继线索(由右孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
} ThreadNode, *ThreadTree;
//辅助全局变量 pre 用于查找当前访问结点的前驱
ThreadNode *pre = NULL; //指向当前访问结点的前驱结点
//二叉树初始化
bool InitThreadTree(ThreadTree &T) {
    ElemType value;
    cin >> value;
    if(value == '#') {
        T = NULL;
    } else {
        T = (ThreadTree)malloc(sizeof(ThreadNode));
        if(!T) { //空间申请失败
            return false;
        }
        T->data = value;
        T->ltag = 0;
        T->rtag = 0;
        InitThreadTree(T->lchild);
        InitThreadTree(T->rchild);
    }
    return true;
}
//二叉树的遍历
void visit(ThreadNode *q) {
    if(!q->lchild) { //左子树为空 建立前驱线索
        q->lchild = pre;
        q->ltag = 1;
    }
    if(pre != NULL && pre->rchild == NULL) {
        pre->rchild = q; //建立前驱结点的后继线索
        pre->rtag = 1;
    }
    pre = q;
}
//先序遍历二叉树 一边遍历一边线索化
void PreThread(ThreadTree T) {
    if(T) {
        visit(T);//访问根结点
        if(T->ltag != 1) { //lchild 不是前驱结点
            PreThread(T->lchild);
        }
        if(T->rtag != 1) { //rchild 不是后继结点 回溯回来会造成死循环
            PreThread(T->rchild);
        }
    }
}
//先序线索化二叉树 T
void CreatePreThread(ThreadTree T) {
    pre = NULL;// pre 初始为NULL
    if(T) {
        PreThread(T);//先序线索化二叉树
        if(pre->rchild == NULL) {
            pre->rtag = 1;    //处理遍历的最后一个结点
        }
    }
}
//先序线索二叉树的遍历
//求先序线索二叉树中结点 p 在先序序列下的后继
ThreadNode *NextNode(ThreadNode *p) {
    if(p->rtag == 0) {
        if(p->lchild != NULL) {
            return p->lchild;
        }
        return p->rchild;
    } else { //rtag == 1 直接返回后继线索
        return p->rchild;
    }
}
//不含头结点的先序线索二叉树的先序遍历算法
void Preorder(ThreadNode *T) {
    for (ThreadNode *p = T; p != NULL; p = NextNode(p)) {
        cout << p->data << " ";
    }
    cout << endl;
}
void test() {
    ThreadTree T;
    InitThreadTree(T);//ABC##DE##F##G##
    CreatePreThread(T);
    cout << "Preorder" << endl;
    Preorder(T);//A B C D E F G
}
int main() {
    test();
    return 0;
}

代码运行结结果: 

4-4 后序线索二叉树

#include <iostream>

using namespace std;

typedef char ElemType;
typedef struct ThreadNode { //线索二叉树结点
    ElemType data;
    struct ThreadNode *lchild, *rchild;
    int ltag, rtag; //左右线索标志
    //    前驱线索(由左孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
    //    后继线索(由右孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
} ThreadNode, *ThreadTree;
//辅助全局变量 pre 用于查找当前访问结点的前驱
ThreadNode *pre = NULL; //指向当前访问结点的前驱结点
//二叉树初始化
bool InitThreadTree(ThreadTree &T) {
    ElemType value;
    cin >> value;
    if(value == '#') {
        T = NULL;
    } else {
        T = (ThreadTree)malloc(sizeof(ThreadNode));
        if(!T) { //空间申请失败
            return false;
        }
        T->data = value;
        T->ltag = 0;
        T->rtag = 0;
        InitThreadTree(T->lchild);
        InitThreadTree(T->rchild);
    }
    return true;
}
//二叉树的遍历
void visit(ThreadNode *q) {
    if(!q->lchild) { //左子树为空 建立前驱线索
        q->lchild = pre;
        q->ltag = 1;
    }
    if(pre != NULL && pre->rchild == NULL) {
        pre->rchild = q; //建立前驱结点的后继线索
        pre->rtag = 1;
    }
    pre = q;
}
//后序遍历二叉树 一边遍历一边线索化
void PostThread(ThreadTree T) {
    if(T) {
        PostThread(T->lchild);//lchild 不是前驱结点
        PostThread(T->rchild);//rchild 不是后继结点
        visit(T);//访问根结点
    }
}
//后序线索化二叉树 T
void CreatePostThread(ThreadTree T) {
    pre = NULL;// pre 初始为NULL
    if(T) {
        PostThread(T);//后序线索化二叉树
        if(pre->rchild == NULL) {
            pre->rtag = 1;    //处理遍历的最后一个结点
        }
    }
}
//后序线索二叉树的遍历
//求后序线索二叉树中结点 p 在后序序列下的前驱
ThreadNode *PreNode(ThreadNode *p) {
    if(p->ltag == 0) {
        if(p->rchild != NULL) {
            return p->rchild;
        }
        return p->lchild;
    } else { //ltag == 1 直接返回后继线索
        return p->lchild;
    }
}
//不含头结点的后序线索二叉树的 逆向 后序遍历算法
void RevPostorder(ThreadNode *T) {
    for (ThreadNode *p = T; p != NULL; p = PreNode(p)) {
        cout << p->data << " ";
    }
    cout << endl;
}
void test() {
    ThreadTree T;
    InitThreadTree(T);//ABC##DE##F##G##
    CreatePostThread(T);
    //Preorder//C E F D B G A
    cout << "RevPostOrder" << endl;
    RevPostorder(T);//A G B D F E C
}
int main() {
    test();
    return 0;
}

代码运行结结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我这么好看

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值