数据结构之二叉树的基本实现

简介: 数据结构之二叉树的基本实现

在我们之前已经了解的堆这样的完全二叉树的实现,也对树型结构有了一些了解,那么今天我们来看看二叉树的一些性质。

因为二叉树是一种每个节点至多只有两个子树(即二叉树的每个节点的度不大于2),并且二叉树的子树有左右之分,其次序不能任意颠倒,因此它的结构也是比较独特的。

1.二叉树的结构定义

二叉树是一种每个节点至多只有两个子树(即二叉树的每个节点的度不大于2),并且二叉树的子树有左右之分,其次序不能任意颠倒。

//定义树的节点
typedef int DATAtype;
typedef struct TreeNode
{
  DATAtype data;
  struct TreeNode* leftchild;
  struct TreeNode* rightchild;
}BTnode;

2.节点构造

简单的节点构造,如同链表的结点,不同的是这里有两个节点表示左孩子与右孩子。

//构造树的节点
BTnode* CreateNode(DATAtype x)
{
  BTnode* newnode = (BTnode*)malloc(sizeof(BTnode));
  if (newnode == NULL)
  {
    perror("malloc fali");
    return NULL;
  }
  newnode->data = x;
  newnode->leftchild = NULL;
  newnode->rightchild = NULL;
  return newnode;
}

3.节点生成树

我们是通过链接节点之间形成树的逻辑关系,这里的树如图:

fca8049ce4a249cdb37f195517908704.png

先链接了六个节点,之后又添加了一个节点

//利用节点生成一个树
BTnode* TreeCreat()
{
  BTnode* node1=CreateNode(1);
  BTnode* node2=CreateNode(2);
  BTnode* node3=CreateNode(3);
  BTnode* node4=CreateNode(4);
  BTnode* node5=CreateNode(5);
  BTnode* node6=CreateNode(6);
  BTnode* node7 = CreateNode(6);
  //建立连接关系
  node1->leftchild = node2;
  node1->rightchild = node4;
  node2->leftchild = node3;
  node4->leftchild = node5;
  node4->rightchild = node6;
  node6->leftchild = node7;
  //返回根
  return node1;
}

3.二叉树的遍历方式

二叉树的遍历方式主要有四种,分别是先序遍历、中序遍历、后序遍历和层次遍历。123

先序遍历:

先访问根节点,再访问左子树,最后访问右子树。

//前序遍历
void Preverorder(BTnode*root)
{
  //根 左子树 右子树
  if (root == NULL)
  {
    return;
  }
  printf("%d ", root->data);
  Preverorder(root->leftchild);
  Preverorder(root->rightchild);
}

中序遍历:

先访问左子树,再访问根节点,最后访问右子树。

void Inorder(BTnode* root)
{
  // 左子树 根  右子树
  if (root == NULL)
  {
    return;
  }
  Preverorder(root->leftchild);
  printf("%d ", root->data);
  Preverorder(root->rightchild);
}

后序遍历

:先访问左子树,再访问右子树,最后访问根节点。

void Postorder(BTnode* root)
{
  // 左子树 右子树 根 
  if (root == NULL)
  {
    return;
  }
  Preverorder(root->leftchild);
  Preverorder(root->rightchild);
  printf("%d ", root->data);
}

层次遍历:

按照从上到下、从左到右的顺序依次访问每个节点。

层序遍历我们使用队列实现,思路:先进先出,上一层出队时带下一层节点入队。

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"queue.h"
#define CRT_SECURE_NO_WARNINGS 1
//定义树的节点
typedef int DATAtype;
typedef struct TreeNode
{
  DATAtype data;
  struct TreeNode* leftchild;
  struct TreeNode* rightchild;
}BTnode;
//构造树的节点
BTnode* CreateNode(DATAtype x)
{
  BTnode* newnode = (BTnode*)malloc(sizeof(BTnode));
  if (newnode == NULL)
  {
    perror("malloc fali");
    return NULL;
  }
  newnode->data = x;
  newnode->leftchild = NULL;
  newnode->rightchild = NULL;
  return newnode;
}
//利用节点生成一个树
BTnode* TreeCreat()
{
  BTnode* node1=CreateNode(1);
  BTnode* node2=CreateNode(2);
  BTnode* node3=CreateNode(3);
  BTnode* node4=CreateNode(4);
  BTnode* node5=CreateNode(5);
  BTnode* node6=CreateNode(6);
  BTnode* node7 = CreateNode(6);
  //建立连接关系
  node1->leftchild = node2;
  node1->rightchild = node4;
  node2->leftchild = node3;
  node4->leftchild = node5;
  node4->rightchild = node6;
  node6->leftchild = node7;
  //返回根
  return node1;
}

层序遍历:

//层序遍历
void leverorder(BTnode* root)
{
  LTnode p;
  Queueinit(&p);
  Queuedestroy(&p);
  //先入根节点
  if (root)
  {
    LTpush(&p, root);
  }
  while (!LTempety(&p))
  {
    //队中数据全是树节点指针型
    BTnode* front = LTfront(&p);
      LTpop(&p);//出队头
      printf("%d", front->data);
         //判断孩子节点
      if (front->leftchild)
      {
        LTpush(&p, front->leftchild);
      }
      if (front->rightchild)
      {
        LTpush(&p, front->rightchild);
      }
  }
  printf("\n");
}

4.求树的所有节点个数

这里有两种方法,除了定义全局变量利用计数的方法来计算树的节点个数,但还需注意全局变量使用后需置零,其次我们也是利用递归的返回值累加计算出节点个数。

//求树的所有节点个数
int size = 0;
int Binarytreesize(BTnode* root)
{
  /*分治思想  从左子树到右子树再到根*/
  if (root == NULL)
  {
    return 0;
  }
  return (1 + Binarytreesize(root->leftchild) + Binarytreesize(root->rightchild));
  /*if (root)
  {
    size++;
    Binarytreesize(root->leftchild);
    Binarytreesize(root->rightchild);
  }
  return size;*/
}

5.求叶子节点个数

寻找递归条件,叶子节点没有左右孩子,否则就不返回一,符合条件的返回一相加。注意递归中返回值的设定。

//求叶子节点个数
int BTreeleavessize(BTnode* root)
{
  //自己的左子树与左右子树为空
  if (root == NULL)
  {
    return 0;
  }
  if (root->leftchild == NULL && root->rightchild == NULL)
  {
    return 1;
  }
  else
  {
    return BTreeleavessize(root->leftchild) + BTreeleavessize(root->rightchild);
  }
}

6.求二叉树树深度

分治思想,两边同时遍历,每有一层加一,左孩子层数与右孩子层数中较大的那个就是深度。

//求二叉树的深度
int BTreeheight(BTnode* root)
{
  //左右同时遍历,选最大的哪一个
  if (root == NULL)
  {
    return 0;
  }
  //这里注意用变量保存一下左 右子树的数目
  int left = BTreeheight(root->leftchild) + 1;
  int right= BTreeheight(root->rightchild) + 1;
  if (left > right)
  {
    return left;
  }
  else
  {
    return right;
  }
}

7.二叉树第K层节点个数

这里的递归主要是找的第k层,利用k==1作为递归返回条件。

//二叉树第k层结点的个数
int BTree_knumber(BTnode* root,int k)
{
  //分情况讨论
  if (root == NULL)
  {
    return 0;
  }
  if (k==1)
  {
    return 1;
  }
  return  BTree_knumber(root->leftchild, k - 1) +
      BTree_knumber(root->rightchild, k - 1);
}

8.返回值为x的节点

这里的难度在与返回值,我们知道在递归里面函数返回值不能直接返回,我们需要判断,对于返回值是需要我们好好检查的,在这里,我们从根,左孩子,右孩子的顺序逐个判断,对于左右孩子并保存返回值,来确定是当前节点。

//返回为x的树节点
BTnode* BTreenode(BTnode* root, DATAtype x)
{
  if (root == NULL)
  {
    return NULL;
  }
  if (root->data == x)
  {
    return root;
  }
  BTnode* left = BTreenode(root->leftchild,x);
  if (left->data==x)
  {
    return left;
  }
  BTnode* right = BTreenode(root->rightchild,x);
  if (right->data==x)
  {
    return right;
  }
  return NULL;
}

一些测试用例:

int main()
{
  BTnode* root = TreeCreat();
  /*Preverorder(root);
  printf("\n");
  Inorder(root);
  printf("\n");
  Postorder(root);*/
  //Binarytreesize(root);
  // BTreeleavessize(root);//BTreeheight(root);
  int x = BTree_knumber(root, 2);
  printf("%d ", BTreenode(root, 2)->data);
  //printf("%d", x);
  return 0;
}


相关文章
数据结构——二叉树的链式结构
数据结构——二叉树的链式结构
36 0
|
1月前
|
存储
数据结构--二叉树(2)
数据结构--二叉树(2)
|
存储 机器学习/深度学习
数据结构--二叉树-堆(1)
数据结构--二叉树-堆(1)
数据结构--二叉树-堆(1)
|
1月前
【数据结构】二叉树的模拟实现
【数据结构】二叉树的模拟实现
|
1月前
|
存储 算法
【数据结构与算法】二叉树基础OJ--下(巩固提高)
【数据结构与算法】二叉树基础OJ--下(巩固提高)
|
27天前
|
算法
【算法与数据结构】二叉树(前中后)序遍历2
【算法与数据结构】二叉树(前中后)序遍历
|
1月前
|
算法
从0开始回顾数据结构---二叉树
二叉树 1、二叉树的建立 层序遍历重建二叉树 测试样例: 11 3 9 20 -1 -1 15 7 -1 -1 -1 -1 中序遍历结果: 9 3 15 20 7 #include<iostream> #include<cstdio> using namespace std; int n, num; //定义一棵二叉树 struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int _val) : val(_val), left(nullptr), right(nullp
|
12天前
二叉树和数据结构
二叉树和数据结构
18 0
|
13天前
|
算法 DataX
二叉树(中)+Leetcode每日一题——“数据结构与算法”“剑指Offer55-I. 二叉树的深度”“100.相同的树”“965.单值二叉树”
二叉树(中)+Leetcode每日一题——“数据结构与算法”“剑指Offer55-I. 二叉树的深度”“100.相同的树”“965.单值二叉树”
|
23天前
|
算法 索引
【算法与数据结构】深入二叉树实现超详解(全源码优化)
【算法与数据结构】深入二叉树实现超详解(全源码优化)