二叉树 的认识

目录

1 二叉树

1.1 基本组成

1.2 如何表示一棵树

1.3 二叉树的基本状态

1.4 如何创建与遍历

2 示例

2.1 创建

2.2 遍历方法

2.2.1 递归

2.2.1.1 实现

2.2.2 栈

2.2.2.1 实现

2.2.2.2 完整实现


1 二叉树

1.1 基本组成

数据域data,左子树LChild,右子树RChild

d94ee17d2d2144a99b19efb0d5c587d2.png

1.2 如何表示一棵树

根节点表示一棵树

1.3 二叉树的基本状态

  • 空的结构体指针:表示一颗NULL

  • 只有根节点的二叉树:左右子树都为NULL

  • 只有左子树:右为NULL

  • 只有右子树:左为NULL

  • 左右子树都健全:满二叉树+完全二叉树

1.4 如何创建与遍历

创建一颗没有规律的二叉树

 struct treeNode
 {
   DataType data; // 存储的数据类型
   struct treeNode* LChild; // 左子树
   struct treeNode* RChild; // 右子树
 };

4727a8ec2c6a4f9aaddb98753258d781.png

2 示例

2.1 创建

现在自己创建一棵树,有ABCDEFGK节点ac2e7e18a1bf476aa05ac912207a7cfe.png

 // 创建树的每个节点
 struct treeNode* createNode(DataType data)
 {
   struct treeNode* newNode = (struct treeNode*)malloc(sizeof(struct treeNode));
   newNode->data = data; // 存储数据
   newNode->LChild = newNode->RChild = NULL; // 左右子树都置空
   return newNode;
 }
   struct treeNode* A = createNode('A'); // 使用上面接口创建节点A
   struct treeNode* B = createNode('B');
   struct treeNode* C = createNode('C');
   struct treeNode* D = createNode('D');
   struct treeNode* E = createNode('E');
   struct treeNode* F = createNode('F');
   struct treeNode* G = createNode('G');
   struct treeNode* K = createNode('K');

创建完了将他们连接起来 ,很明显B,C连接在根A后,同理,D,E连接在根B后

 void insertNode(struct treeNode* curNode, 
 struct treeNode* LchildNode, struct treeNode* RchildNode)
 {
   curNode->LChild = LchildNode; // 传过来的左子树设置为根的左子树
   curNode->RChild = RchildNode; // 同理,右子树
 }
   insertNode(A, B, C); // A为根,B为左子树,C为右子树
   insertNode(B, D, E); // 同理
   insertNode(C, F, G);
   insertNode(F, NULL, K);

2.2 遍历方法

c3ba794243ec40c1acbf2df2bd534a98.png

2.2.1 递归

接口函数-中序遍历

 void midOrder(struct treeNode* tree)
 {
   if (tree != NULL)
   {
     midOrder(tree->LChild); // 将根tree的 左 子树作为新根,再次进入该递归
     printData(tree);    // 打印根tree的数据
     midOrder(tree->RChild); // 将根tree的 右 子树作为新根,再次进入该递归
   }
 }

若是前序遍历,则将根tree的打印提前即可

 // 4. 前序遍历 函数
 void preOrder(struct treeNode* tree)
 {
   if (tree != NULL)
   { 
     printData(tree);
     preOrder(tree->LChild);
     preOrder(tree->RChild);
   }
 }

若是后序遍历,则将根tree的打印放后即可

// 6. 后序遍历 函数
 void postOrder(struct treeNode* tree)
 {
   if (tree != NULL)
   {
     postOrder(tree->LChild);
     postOrder(tree->RChild);
     printData(tree);
   }
 }

下面使用中序遍历:

e7f197d97f6941ce9a39031869ecd1e4.png

2.2.1.1 实现

创建递归函数,传根tree(A)进来

 midOrder(A);

b925eaff30da49adb2c9fc1b5e20dea3.png

由于是中序遍历,所以首先从左子树(B)开始,再次进入遍历函数

28c139bddb574fec9d9b5f237faa1e29.png

然后,从2中左子树(D)开始,再次进入遍历函数

a111a46325b54d329f7f8c5469749fdb.png

D作为根开始再次进入遍历函数,不过其左子树为NULL,退出遍历函数,

83698faa488f40009ddeefb101f4564a.png

进入打印函数D,

f261ea6b6d0b4029bedec697fa572aa1.png

而后进入右子树,又为NULL,退出D作为根的遍历函数。

0eab0765c694492b97772157b548f764.png

进入打印函数B,

d4d03c962cb44b70ae77ac32ff8749c0.png

而后进入E作为根的遍历函数,

情况同D进入左子树NULL,退出,打印E,进入右子树E,NULL,

退出E作为根的遍历函数

9b6872b5afcd4a41b76c067f1080cd00.png

退出后打印A,

再次进入右子树以C为根的遍历函数

4e4531b63a974d5b924f1684ae0251dd.png

过程同B,不再赘述。

结果:相同

e4159896a5f3429aaac60a86be4e23d1.png

2259cd7d85e545db96ae5d0c3b89c2fa.png

2.2.2 栈

2.2.2.1 实现

初始化一个栈,给定大小, 栈顶设为-1(第一个元素入栈即为0,对应下标刚好0)

// 初始化一个栈,给定大小10
     struct treeNode* stack[10];
     int stackTop = -1; // 栈顶-1,入完第一个数据成0,刚好栈下标0开始

传 根tree(A)进入

   midOrderByStack(A);

直接走左边一条路,走一个节点,将一个节点的数据存入栈,3b4b33c3a3b84efa8eea9caef42d233d.png

栈顶++,并将下一个左子树赋给curNode

 while (curNode)
       {
         stackTop++; // 栈顶+1
         stack[stackTop] = curNode;// 保存每个节点到栈里
         curNode = curNode->LChild;// 保存下一个左子树到curNode里,
                                           // 以便循环进入下一个左子树
       }

如果curNode为空,说明左边遍历完了,已经没有左子树

c2669770afaa4889898cd76fae483c36.png

先取出最后一个节点(D)的数据,打印后,栈顶--,将右子树赋给curNode

if (stackTop != -1)
       {
         curNode = stack[stackTop];// 将最后一个节点出栈
         printf("%c ", curNode->data);
         stackTop--; // 栈顶-1
         curNode = curNode->RChild;
       }
2.2.2.2 完整实现
void midOrderByStack(struct treeNode* tree)
 {
   //  树为空
   if (tree == NULL)
   {
     return;
   }
   else
   {
     // 初始化一个栈,给定大小10
     struct treeNode* stack[10];
     int stackTop = -1; // 栈顶-1,入完第一个数据成0,刚好栈下标0开始
     
     struct treeNode* curNode = tree;
     while (stackTop != -1 || curNode)
     {
       // 走所有的左子树
       while (curNode)
       {
         stackTop++; // 栈顶+1
         stack[stackTop] = curNode;// 保存每个节点到栈里
         curNode = curNode->LChild;// 保存下一个左子树到curNode里,以便循环进入下一个左子树
       }
       if (stackTop != -1)
       {
         curNode = stack[stackTop];// 将最后一个节点出栈
         printf("%c ", curNode->data);
         stackTop--; // 栈顶-1
         curNode = curNode->RChild;
       }
     }
   }
 }

结果:

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值