数据结构—树(二叉树)

#define _CRT_SECURE_NO_WARNINGS 1

//树:非线性的数据结构,由有限个节点组成一个具有层次关系的集合。像是一颗倒挂的树,所以叫树。
//树的相关概念:
//1、节点的度:一个节点含有的子树的个数成为节点的度
//2、叶节点(终端节点):度为0的节点称为终端节点,(子节点为空的节点)
//3、非终端节点(分支节点):度不为0的节点,即(子节点不为空的节点)
//4、双亲节点(父节点):若一个节点含有子节点,称该节点为子节点的父节点
//5、孩子节点(子节点):一个节点含有的子树的根节点称为该节点的子节点
//6、兄弟节点:具有相同父节点的节点称为兄弟节点
//7、树的度:一棵树中,最大的节点的度称为树的度
//8、节点的层次:从根开始定义起,根为第一层,根的子节点为第二层,以此类推
//9、树的高度或深度:树中节点的最大层次
//10、堂兄弟节点:双亲在同一层的节点互为堂兄弟节点
//11、节点的祖先:从根到该节点所经分支上的所有节点
//12、子孙:以某节点为根的子树中的任一节点,都称为该节点的子孙
//13、森林:多棵不想交的树的集合称为森林
//
//
//树的每个节点又有子节点。没有父节点的节点称为根节点。每个非根节点有且只有一个父节点,每个子节点可以分成多个不相交的子树。
//
//树的存储方式有多种,如双亲表示法、孩子表示法、孩子兄弟表示法。
//1、双亲表示法:用连续的空间存储每个节点,每个节点中有一个指向双亲节点地址的指针。容易找到双亲节点,不易找到孩子节点。
//2、孩子表示法:将每个节点的孩子节点用链表链接起来,容易找到孩子节点,但是不容易找到双亲节点。
//3、孩子兄弟表示法:在每个节点中,保存一个指向自己第一个孩子节点的指针,还保存一个指针自己下一个兄弟节点的指针。
//
//树的应场景:人工智能中的决策树、MYSQL数据库索引、文件系统的目录结构等。
//
//二叉树:有限个节点集合,该集合为空,或者是由一个根节点加一棵左子树和一棵右子树组成的两个分支的树结构。
//二叉树的特点:每个节点最多有两棵子树,二叉树的两个子树分别称为左右子树,次序不能颠倒。
//五种基本形式:一个空节点、 只有一个非空节点、 根节点有一棵左子树、 根节点有一棵右子树、 根节点有左右子树
//
//满二叉树:每一层节点数都达到最大值的二叉树。(除了最后一层叶子节点,其它每个节点都有左右棵子树),层数为 K ,节点数为 (2^k-1)。
//完全二叉树:深度为 K ,有 n 个节点的二叉树,当且仅当其每一个节点都与深度为 K 的满二叉树中编号从1到 n 的节点一一对应。
//           (相同高度的完全二叉树叶子节点这一层,从最右边一个右往左依次缺失部分子树。)
//           (满二叉树是一种特殊的完全二叉树)
//二者的区别: 满二叉树的每一层,节点个数都达到最大值,也就是除了叶子节点那一层,每一层的父节点都有不为空的左右子树.
//            完全二叉树的最后一层的节点个数可能没有达到最大值。
//
//二叉树的顺序存与链式存储
//顺序存储:使用数组来存储,一般只适合用来表示完全二叉树,因为不是完全二叉树会有空节点造成空间浪费,现实中只有堆才会用数组存储。
//          二叉树顺序存储在物理上是数组,在逻辑上是二叉树。
//
//链式存储:用链表来表示二叉树,用链来指示元素的逻辑关系。通常的方法是链表中每个节点由数据域和左右指针域三部分组成。
//          数据域保存值,左右指针保存左右孩子节点的地址。
//
//二叉树有三种遍历方式:前序遍历、中序遍历、后序遍历
//
//实现二叉树以下操作。
// 1. 创建二叉树
//BTNode* CreateBinTree(BTDataType* array, int size);
//
// 销毁二叉树
//void DestroyTree(BTNode** pRoot);
//
// 二叉树的三种遍历方式
//void PreOrder(BTNode* pRoot);
//void InOrder(BTNode* pRoot);
//void PostOrderNor(BTNode* pRoot);
//
//void LevelOrder(BTNode* pRoot);
//
// 获取二叉树中节点的个数
//int GetNodeCount(BTNode* pRoot);
//
// 求二叉树的高度
//int Height(BTNode* pRoot);
//
// 获取二叉数中叶子节点的个数
//int GetLeafNodeCount(BTNode* pRoot);
//
// 获取二叉树第K层节点的个数
//int GetKLevelNodeCount(BTNode* pRoot, int K);
//
// 获取二叉树中某个节点的双亲节点
//BTNode* GetNodeParent(BTNode* pRoot, BTNode* pNode);

#pragma once

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

typedef struct Node {
    int  value;
    struct Node *left;    // 指向左孩子节点
    struct Node *right;    // 指向右孩子节点
}    Node;

// 前序遍历
void preOrderTraversal(Node *root)
{
    if (root == NULL)
    {
        return;
    }
    printf("%d ", root->value);
    preOrderTraversal(root->left);
    preOrderTraversal(root->right);
}

// 中序遍历
void inOrderTraversal(Node *root)
{
    if (root == NULL)
    {
        return;
    }
    inOrderTraversal(root->left);
    printf("%d ", root->value);
    inOrderTraversal(root->right);
}

 //后序遍历
void postOrderTraversal(Node *root)
{
    if (root == NULL)
    {
        return;
    }
    postOrderTraversal(root->left);
    postOrderTraversal(root->right);
    printf("%d ", root->value);
}

//通过中序遍历来实现节点个数统计
 int count = 0;
void getNodeCount(Node *root)
{
    if (root == NULL)
    {
        return;
    }

    getNodeCount(root->left);
    count++;
    getNodeCount(root->right);
}

//通过后序遍历来实现节点个数统计
int getNodeCount2(Node *root)
{
    if (root == NULL)
    {
        return 0;
    }

    int left = getNodeCount2(root->left);
    int right = getNodeCount2(root->right);

    return left + 1 + right;
}

int myMax(int a, int b)
{
    return a >= b ? a : b;
}

//获取二叉树的高度
int getHeight(Node *root)
{
    if (root == NULL)
    {
        return 0;
    }
    //分别对获取左右子树的高度,然后返回最大的值
    int left = getHeight(root->left);
    int right = getHeight(root->right);

    return left >= right ? left : right;
    //返回值封装成函数
    return myMax(left, right) + 1;

}

//统计叶子节点的个数
int getLeafCount(Node *root)
{
    if (root == NULL)
    {
        return 0;
    }
    //每找到一个节点,它的左右子树都是空节点时返回一个1
    else if (root->left == NULL && root->right == NULL)
    {
        return 1;
    }
    else
    {
        //递归分别对左子树和右子树的叶子节点进行统计
        return getLeafCount(root->left) + getLeafCount(root->right);
    }
}

//k层节点个数
int getKLevelCount(Node *root, int k)
{
    assert(k >= 1);

    if (root == NULL)
    {
        return 0;
    }
    else if (k == 1)
    {
        return 1;
    }
    else
    {
        return getKLevelCount(root->left, k - 1)
            + getKLevelCount(root->right, k - 1);
    }
}

//二叉树中查找指定值
Node * find(Node *root, int v)
{
    if (root == NULL)
    {
        return NULL;    // 没有找到
    }

    if (root->value == v)
    {
        return root;
    }

    Node * left = find(root->left, v);
    if (left != NULL)
    {
        return left;
    }

    Node * right = find(root->right, v);
    if (right != NULL)
    {
        return right;
    }
    else
    {
        return NULL;
    }
}

//销毁二叉树

void DestroyTree(Node *node)
{
    Node *head = NULL;
    Node *prev = NULL;
    node->left = prev;
    if (prev == NULL)
    {
        head = node;
    }
    else
    {
        prev->right = node;
    }

    prev = node;
}

//创建树
Node * createTree(int *arr, int size)
{
//将数组中的值放到节点中
    Node *n1 = (Node *)malloc(sizeof(Node));
    n1->value = arr[0];
    Node *n2 = (Node *)malloc(sizeof(Node));
    n2->value = arr[1];
    Node *n3 = (Node *)malloc(sizeof(Node));
    n3->value = arr[2];
    Node *n4 = (Node *)malloc(sizeof(Node));
    n4->value = arr[3];
    Node *n5 = (Node *)malloc(sizeof(Node));
    n5->value = arr[4];
    Node *n6 = (Node *)malloc(sizeof(Node));
    n6->value = arr[5];
    Node *n7 = (Node *)malloc(sizeof(Node));
    n7->value = arr[6];
    Node *n8 = (Node *)malloc(sizeof(Node));
    n8->value = arr[7];
  //将节点链接成树
    n1->left = n2; n1->right = n3;
    n2->left = n4; n2->right = n5;
    n3->left = n6; n3->right = n7;
    n4->left = NULL; n4->right = NULL;
    n5->left = NULL; n5->right = n8;
    n6->left = NULL; n6->right = NULL;
    n7->left = NULL; n7->right = NULL;

    return n1;
}

int main()
{
    int arr[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    int size = sizeof(arr) / sizeof(arr[0]);

    //创建树
    Node* n1=createTree(arr, size);

    // 1 2 3 4 5 6 7 8
    // a b c d e f g h
    //递归方式实现三种遍历。通过打印值来看遍历的顺序
    preOrderTraversal(n1); printf("\n"); //1 2 4 5 8 3 6 7
    inOrderTraversal(n1); printf("\n");  //4 2 5 8 1 6 3 7
    postOrderTraversal(n1); printf("\n");//4 8 5 2 6 7 3 1

    system("pause");
    return 0;
}

原文地址:https://www.cnblogs.com/fengkun/p/11253508.html

时间: 2024-08-29 07:36:44

数据结构—树(二叉树)的相关文章

数据结构与算法-----&gt;数据结构-----&gt;树-------&gt;二叉树的遍历

二叉树的遍历 第一部分 基本概念以及编程实现 概述: 遍历树,就是指按照一定的顺序访问树中的所有节点. 遍历树有三种常用方法,分别是中序遍历(inorder).前序遍历(preorder).后序遍历(postorder) 三种遍历方法的三个步骤都是相同的,只不过这三个步骤的执行顺序不同.三种遍历方式的名称的由来是根据""访问节点内容""这个步骤的执行时间来定的,这个步骤在第一步执行的是前序遍历,在第二步执行的是中序遍历,在第三步执行的是后序遍历. 1.1中序遍历(i

数据结构---树、二叉树、森林

1.基本术语: 度:有两种度"结点的度"与"树的度".结点的度指的是一个结点子树的个数:树的度是指树中结点度的最大值. 叶子结点:指的是没有子树的结点. 层:树是有层次的,一般根结点为第0层.规定根结点到某结点的路径长度为该结点的层数. 深度:树中结点的最大层数 兄弟:同一双亲的结点,互为兄弟 堂兄弟:双亲在同一层次的结点,互为堂兄弟 祖先:从根结点到该结点的路径上的所有结点都是该结点的祖先. 子孙:以某一结点为根的子树上的所有结点都是该结点的子孙 森林:n棵互不相

python数据结构树和二叉树简介

一.树的定义 树形结构是一类重要的非线性结构.树形结构是结点之间有分支,并具有层次关系的结构.它非常类似于自然界中的树.树的递归定义:树(Tree)是n(n≥0)个结点的有限集T,T为空时称为空树,否则它满足如下两个条件:(1)有且仅有一个特定的称为根(Root)的结点:(2)其余的结点可分为m(m≥0)个互不相交的子集Tl,T2,…,Tm,其中每个子集本身又是一棵树,并称其为根的子树(Subree). 二.二叉树的定义 二叉树是由n(n≥0)个结点组成的有限集合.每个结点最多有两个子树的有序树

数据结构之二叉树查找

数据结构之--二叉树查找 定义:它是一棵树,或者具有以下性质的树.  若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值:  它的左.右子树也分别为二叉排序树: 图解: ?        ?    ?    ?    ?    ?? #include<stdio.h> #include<stdlib.h> typedef int Status; #define TRUE 1 #define FALSE 0 t

数据结构--树的一些计算

先解释一下一些最基本的概念 结点的孩子结点个数即为该结点的度.度为0的结点叫叶子结点.处在树的最顶端(没有双亲)的结点叫根结点. 介绍一下公式 k:总度数k+1:总节点数 为什么总节点数肯定比总度数多1呢?其实很简单可以解释,度可以看作节点与节点之间的线,多1就是显而易见的 设该二叉树总结点数为N,叶子结点个数为n0,度为1的结点个数为n1.度为2的节点个数为n2下面可得两等式:(1) N = n2 + n0 + n1;依据:很显然,二叉树总结点数等于度分别为0,1,2的结点个数总和.(2) N

数据结构之二叉树的遍历汇总

声明:小弟写博客不久,主要是边上班边学习边写博客,如果错误,望各位包涵并指导. 二叉树是一种常用的非线性数据结构,二叉树是由一个根节点和称为根的左.右子树的两颗互不相交的二叉树构成.二叉树具有一些特殊的性质,如第i层上最多有2^(i-1)个结点.二叉树的链式存储结构如下: typedef struct BTNode { char data; //字符型数据; struct BTNode* lChild,*rChild; //左右子结点的指针; }BTNode,*BiTree; data为二叉树中

采用栈数据结构的二叉树遍历

[前言]树的遍历,根据访问自身和其子节点之间的顺序关系,分为前序,后序遍历.对于二叉树,每个节点至多有两个子节点(特别的称为左,右子节点),又有中序遍历.由于树自身具有的递归性,这些遍历函数使用递归函数很容易实现,代码也非常简洁.借助于数据结构中的栈,可以把树遍历的递归函数改写为非递归函数. 在这里我思考的问题是,很显然,循环可以改写为递归函数.递归函数是否借助栈这种数据结构改写为循环呢.因为函数调用中,call procedure stack 中存储了流程的 context,调用和返回相当于根

数据结构 - 树和森林表示与遍历

双亲表示法(顺序存储结构) 用一组连续的存储空间来存储树的结点,同时在每个结点中附加一个指示器(整数域) ,用以指示双亲结点的位置(下标值) .数组元素及数组的类型定义如下: #define MAX_SIZE 100 typedef struct PTNode { ElemType data ; int parent ; }PTNode ; typedef struct { PTNode Nodes[MAX_SIZE] ; int root; /* 根结点位置 */ int num ; /* 结

纸上谈兵: 树, 二叉树, 二叉搜索树

树的特征和定义 树(Tree)是元素的集合.我们先以比较直观的方式介绍树.下面的数据结构是一个树: 树有多个节点(node),用以储存元素.某些节点之间存在一定的关系,用连线表示,连线称为边(edge).边的上端节点称为父节点,下端称为子节点.树像是一个不断分叉的树根. 每个节点可以有多个子节点(children),而该节点是相应子节点的父节点(parent).比如说,3,5是6的子节点,6是3,5的父节点:1,8,7是3的子节点, 3是1,8,7的父节点.树有一个没有父节点的节点,称为根节点(

python环境下使用mysql数据及数据结构和二叉树算法(图)

python环境下使用mysql数据及数据结构和二叉树算法(图):1 python环境下使用mysql2使用的是 pymysql库3 开始-->创建connection-->获取cursor-->操作-->关闭cursor->关闭connection->结束45 代码框架6 import pymysql.cursors7 ###连接数据库8 connection = pymysql.connect(host='127.0.0.1',port=3306,user='roo