• 二叉树的操作


    目录

    链式存储结构

    先序遍历二叉树

    递归算法

    非递归算法

    中序遍历二叉树

    递归算法

    非递归算法

    后序遍历二叉树

    递归算法

    非递归算法

    层次遍历二叉树

    线索树

    用土方法找到中序前驱

    中序线索化

    先序线索化

    线索二叉树找后继

    线索二叉树找前驱

    线索二叉树的遍历


    链式存储结构

    1. struct ElemType{
    2. int value;
    3. };
    4. typedef struct BiTNode{
    5. ElemType data;
    6. struct BiTNode *lchild,*rchild;
    7. }BiTNode,*BiTree;
    8. //定义一颗空树
    9. BiTree root=NULL;
    10. //插入根节点
    11. root=(BiTNode)malloc(sizeof(BiTNode));
    12. root->data={1};
    13. root->lchild=NULL;
    14. root->rchild=NULL;
    15. //插入新节点
    16. BiTNode *p=(BiTNode *)malloc(sizeof(BiTNode));
    17. p->data={2};
    18. p->lchild=NULL;
    19. p->rchild=NULL;
    20. root->lchild=p;//作为根节点的左孩子

    先序遍历二叉树

    递归算法

    若二叉树为空,则遍历结束:否则

    1. 访问根节点
    2. 先序遍历左子树(递归调用本算法)
    3. 先序遍历右子树

    1. //先序遍历的递归算法
    2. void PreorderTraverse(BTNode *T){
    3. if(T!=NULL){
    4. visit(T->data);//访问根节点
    5. PreorderTraverse(T->Lchild);
    6. PreorderTraverse(T->Rchild);
    7. }
    8. }

    非递归算法

    设T是指向二叉树根节点的指针变量,非递归算法是:

    若二叉树为空,则返回:否则,令p=T;

    1. 访问p所指向的节点
    2. q=p->Rchild,若q不为空,则q进栈
    3. p=p->Lchild,若p不为空,转(1)否则转(4)
    4. 退回到p,转(1),直到栈空为止。

    1. #define MAX_NODE 50
    2. void PreorderTraverse(BTNode *T){
    3. BTNode *Stack[MAX_NODE],*p=T,*q;
    4. int top=0;
    5. if(T==NULL){
    6. printf("Binary Tree is Empty!\n");
    7. }
    8. else{
    9. do{
    10. visit(p->data);
    11. q=p->Rchild;
    12. if(q!=NULL)
    13. stack[++top]=q;
    14. p=p->Lchild;
    15. if(p==NULL){
    16. p=stack[top];
    17. top--;
    18. }
    19. }while(p!=NULL);
    20. }
    21. }

    中序遍历二叉树

    递归算法

    若二叉树为空,则遍历结束;否则:

    1. 中序遍历左子树
    2. 访问根节点
    3. 中序遍历右子树

    1. void InorderTraverse(BTNode *T){
    2. if(T!=NULL){
    3. InorderTraverse(T->Lchild);
    4. visit(T->data);
    5. InorderTraverse(T->Rchild);
    6. }
    7. }

    非递归算法

    设T是指向二叉树根节点的指针变量,非递归算法是:

    若二叉树为空,则返回;否则令p=T;

    1. 若p不为空,p进栈,p=p->Lchild,一直循环;
    2. 否则(p为空),退栈到p,访问p所指向的节点
    3. p=p->Rchild,转(1)

    1. #define MAX_NODE 50
    2. void InorderTraverse(BTNode *T){
    3. BTNode *stack[MAX_NODE],*p=T;
    4. int top=0,bool=1;
    5. if(T==NULL)
    6. printf("Binary Tree is Empty!\n");
    7. else{
    8. do{
    9. while(p!=NULL){
    10. stack[++top]=p;
    11. p=p->Lchild;
    12. }
    13. if(top==0){
    14. bool=0;
    15. }
    16. else{
    17. p=stack[top];
    18. top--;
    19. vist(p->data);
    20. p=p->Rchild;
    21. }
    22. }while(bool!=0);
    23. }
    24. }

    后序遍历二叉树

    递归算法

    1. void InorderTraverse(BTNode *T){
    2. if(T!=NULL){
    3. InorderTraverse(T->Lchild);
    4. InorderTraverse(T->Rchild);
    5. visit(T->data);
    6. }
    7. }

    非递归算法

    1. #define MAX_NODE 50
    2. void PostorderTraverse(BTNode *T){
    3. BTNode *S1[MAX_NODE],*p=T;
    4. int S2[MAX_NODE],top=0,bool=1;
    5. if(T==NULL)
    6. printf("Binary Tree is Empty!\n");
    7. else{
    8. do{
    9. while(p!=NULL){
    10. S1[++top]=p;
    11. S2[top]=0;
    12. p=p->Lchild;
    13. }
    14. if(top==0)
    15. bool=0;
    16. else if(S2[top]==0){
    17. p=S1[top]->Rchild;
    18. S2[top]=1;
    19. }
    20. else{
    21. p=S1[top];
    22. top--;
    23. visit(p->data);
    24. p=NULL;
    25. }while(bool!=0);
    26. }
    27. }
    28. }

    层次遍历二叉树

    层次遍历二叉树,是从根节点开始遍历,按层次次序“”“自上而下,从左到右”访问树中各个节点。为保证是按层次遍历,必须设置一个队列,初始化时为空。设T是指向根节点的指针变量,层次遍历费递归算法是:

    1. 初始化一个辅助队列
    2. 根节点入队
    3. 若队列非空,则队头节点出队,访问该节点,并将其左右孩子插入队尾;’
    4. 重复3直至队列为空

    1. #define MAX_NODE 50
    2. void LevelorderTraverse(BTNode *T){
    3. BTNode *Queue[MAX_NODE],*p=T;
    4. int front=0,rear=0;
    5. if(p!=NULL){
    6. Queue[++rear]=p;
    7. while(front
    8. p=Queue[++front];
    9. visit(p->data);
    10. if(p->Lchild!=NULL)
    11. Queue[++rear]=p->Lchild;
    12. if(p->Rchild!=NULL)
    13. Queue[++rear]=p->Rchild;
    14. }
    15. }
    16. }

    线索树

    遍历二叉树是按照一定的规则将树中的节点排列成一个线性序列,即对非线性结构的线性操作。如何找到遍历过程中动态得到的每个节点的直接前驱和直接后继?如何保存这些信息。

    设一颗二叉树有n个节点,则有n-1条边,而n个节点共有2n个指针域,显然有n+1个空闲指针域未用,则可以利用这些空闲指针域来存储节点的直接前驱和直接后继。

    若节点有左孩子,则Lchild指向左孩子,否则指向其直接前驱;

    若节点有右孩子,则Rchild指向右孩子,否则直线其直接后继;

    为避免混淆,对节点结构加以改进,增加两个标志域,

    Lchild  Ltag  data  Rchild  Rtag

    Ltag=0:Lchild指示节点的左孩子

            =1:Lchild指示节点的前驱

    用这种节点结构构成的二叉树的存储结构;叫做线索链表;指向节点前驱和后继的指针叫做线索;按照某种层次遍历,加上线索二叉树称之为线索二叉树;

    1. //线索二叉树的节点结构与示例
    2. typedef struct BiThrNode{
    3. ElemType data;
    4. struct BiThrNode *Lchild,*Rchild;
    5. int Ltag,Rtag;
    6. }ThreadNode,*ThreadTree;

    用土方法找到中序前驱

    1. void InOrder(BiTree T){
    2. if(T!=NULL){
    3. InOrder(T->lchild);
    4. visit(T);
    5. InOrder(T->rchild);
    6. }
    7. }
    8. //访问节点q
    9. void visit(BiTNode *q){
    10. if(q==p)//当前访问的刚好是p节点
    11. final=pre;
    12. else
    13. pre=q;//pre指向当前访问的节点
    14. }
    15. //辅助全局变量,用于查找p的前驱
    16. BiTNode *p;//p指向目标节点
    17. BiTNode *pre=NULL; //指向当前访问节点的前驱
    18. BiTNode *final=NULL;//用于记录最终结果

    中序线索化

    1. //中序遍历二叉树,一边遍历一边线索化
    2. void InThread(ThreadTree T){
    3. if(T!=NULL){
    4. InThread(T->lchild);
    5. visit(T);
    6. InThread(T->rchild);
    7. }
    8. }
    9. void visit(ThreadNode *q){
    10. if(q->lchild==NULL){
    11. q->lchild=pre;
    12. q->ltag=1;
    13. }
    14. if(pre!=NULL&&pre->rchild==NULL){
    15. pre->rchild=q;//建立前驱节点的后继线索
    16. pre->rtag=1;
    17. }
    18. pre=q;
    19. }
    20. ThreadNode *pre=NULL;
    21. //中序线索化二叉树
    22. void CreateInThread(ThreadTree T){
    23. pre=NULL;
    24. if(T!=NULL){
    25. InThread(T);
    26. if(pre->rchild==NUll){
    27. pre->rtag=1;//处理遍历的最后一个节点
    28. }
    29. }
    30. }

    先序线索化

    1. void InThread(ThreadTree T){
    2. if(T!=NULL){
    3. visit(T);
    4. if(T->ltag==0)//lchild不是前驱线索
    5. InThread(T->lchild);
    6. InThread(T->rchild);
    7. }
    8. }

    线索二叉树找后继

    1. //中序线索二叉树找中序后继
    2. //找到以P为根的子树中,第一个被中序遍历的节点
    3. ThreadNode *Firstnode(ThreadNode *p){
    4. while(p->ltag==0)
    5. p=p->lchild;
    6. return p;
    7. }
    8. //在中序线索二叉树中找到节点p的后继节点
    9. ThreadNode *Nextnode(ThreadNode *p){
    10. //右子树中最左下节点
    11. if(p->rtag==0)
    12. return Firstnode(p->rchild);
    13. else
    14. return p->rchild;//rtag==1直接返回后继线索
    15. }
    16. //对中序线索二叉树进行中序遍历(利用线索实现的非递归算法)
    17. void Inorder(ThreadNode *T){
    18. for(ThreadNode *p=Firstnode(T);p!=NULL;p=Nextnode(p))
    19. visit(p);
    20. }

    线索二叉树找前驱

    1. //找到以P为根的子树中,最后一个被中序遍历的节点
    2. ThreadNode *Lastnode(ThreadNode *p){
    3. while(p->rtag==0)
    4. p=p->rchild;
    5. return p;
    6. }
    7. //在中序线索二叉树中找到节点p的前驱节点
    8. ThreadNode *Prenode(ThreadNode *p){
    9. //左子树中最右下节点
    10. if(p->ltag==0)
    11. return Lastnode(p->lchild);
    12. else
    13. return p->lchild;//ltag==1直接返回前驱线索
    14. }
    15. //对中序线索二叉树进行逆向中序遍历
    16. void RevInorder(ThreadNode *T){
    17. for(ThreadNode *p=Lastnode(T);p!=NULL;p=Prenode(p))
    18. visit(p);
    19. }

    线索二叉树的遍历

    1. //先序二叉树的先序遍历
    2. void preorder_Thread_bt(BiThrNode *T){
    3. BiThrNode *p=T;
    4. while(p!=NULL){
    5. visit(p->data);
    6. if(p->Ltag==0)
    7. p=p->Lchild;
    8. else
    9. p=p->Rchild;
    10. }
    11. }
    12. //中序线索二叉树的中序遍历
    13. void inorder_Thread_bt(BiThrNode *T){
    14. BiThrNode *p;
    15. while(T!=NULL){
    16. p=T;
    17. while(p->Ltag==0)
    18. p=p->Lchild;
    19. while(p!=NULL){
    20. visit(p->data);
    21. if(p->Rtag==1)
    22. p=p->Rchild;
    23. else{
    24. p=p->Rchild;
    25. while(p->Ltag==0){
    26. p=p->Lchild;
    27. }
    28. }
    29. }
    30. }
    31. }

  • 相关阅读:
    数据在内存中的存储
    大数据在电力行业的应用案例100讲(二十八)-电力营销系统规则配置的实现与应用
    Android Studio更新新版本后无法创建flutter项目
    Unity使用Visual Studio Code 调试
    Caddy Web服务器深度解析与对比:Caddy vs. Nginx vs. Apache
    EndNote21 | 账户同步问题
    uni-app实现图片预览
    awk常用统计命令
    关于一维数组的扩容
    基于抽象语法树的神经网络模型(ASTNN)简介
  • 原文地址:https://blog.csdn.net/m0_59073956/article/details/127784764