首页 > 其他分享 >数据结构之二叉树(c语言版)

数据结构之二叉树(c语言版)

时间:2024-04-11 11:45:21浏览次数:16  
标签:结点 遍历 data 二叉树 input 数据结构 root 语言版

之前的都是线性结构,而树结构在计算机应用中的应用更加广泛。linux中的目录结构,某些数据库的底层存储等,都是采用树结构进行构架的。

树的概念

线性表是一对一的关系,而树是一对多的关系。

树的结点:包含一个数据元素及若干指向子树的分支;
孩子结点:结点的子树的根称为该结点的孩子;
双亲结点:B 结点是A 结点的孩子,则A结点是B 结点的双亲;
兄弟结点:同一双亲的孩子结点; 堂兄结点:同一层上结点;
祖先结点: 从根到该结点的所经分支上的所有结点
子孙结点:以某结点为根的子树中任一结点都称为该结点的子孙
结点层:根结点的层定义为1;根的孩子为第二层结点,依此类推;
树的深度:树中最大的结点层
结点的度:结点子树的个数
树的度: 树中最大的结点度。
叶子结点:也叫终端结点,是度为 0 的结点;
分枝结点:度不为0的结点;
有序树:子树有序的树,如:家族树;
无序树:不考虑子树的顺序;

二叉树

最常用的树结构是二叉树。在计算机科学中,二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”和“右子树”。

1. 二叉树的性质

二叉树有以下几个性质:TODO(上标和下标)
性质1:二叉树第i层上的结点数目最多为 2****{i-1} (i≥1)。
性质2:深度为k的二叉树至多有2{k}-1个结点(k≥1)。
性质3:包含n个结点的二叉树的高度至少为log2 (n+1)
性质4:在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1

2、二叉树的种类

完全二叉树

若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。

满二叉树

除了叶子结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树

平衡二叉树

它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

3、二叉树的遍历方式

先序遍历

先访问根节点,先序遍历左子树,先序遍历右子树

中序遍历

中序遍历左子树,访问根节点,中序遍历右子树

后序遍历

后序遍历左子树,后序遍历右子树,访问根节点

层次遍历

即按照层次访问,通常用队列来做。访问根,访问子女,再访问子女的子女

4、二叉树的存储方式

1、顺序存储

用一组连续的存储单元存放二叉树的数据元素。结点在数组中的相对位置蕴含着结点之间的关系。

比较浪费空间,基本不用。

2、链式存储

链式存储结构的每个结点由数据域、左指针域和右指针域组成。左指针和右指针分别指向下一层的二叉树。

在这里插入图片描述

二叉树的实现

使用链式结构来作为底层:

先初始化树,以先序遍历的方式创建树,输入的值为0时代表该节点为NULL,通过递归实现节点的建立:

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

typedef struct tree{
    int data;
    struct tree *lchild,*rchild;
}Tree;

//初始化树,先序
Tree *init(Tree *root){
    root=NULL;

    int p=0;
    printf("input data\n");
    scanf("%d",&p);

    if(0!=p){
        root=(Tree *)malloc(sizeof(Tree));
        root->data=p;
        printf("The data is %d\n",p);

        printf(" 请输入左字树data \n");
        root->lchild=init(root->lchild);
        
		printf(" 请输入右字树data \n");
        root->rchild=init(root->rchild);
        
    }
    return root;

}

三种遍历方式:

//先序遍历
void preOrder(Tree *root){
    if(root==NULL){
        return ;
    }
    printf("%d  ",root->data);
    preOrder(root->lchild);
    preOrder(root->rchild);
}

//后序遍历
void lastOrder(Tree *root){
     if(root==NULL){
        return ;
    }
    lastOrder(root->lchild);
    lastOrder(root->rchild);
    printf("%d  ",root->data);
}

//中序遍历
void midOrder(Tree *root){
     if(root==NULL){
        return ;
    }
    midOrder(root->lchild);
    printf("%d  ",root->data);
    midOrder(root->rchild);
    
}

为了测试,我们需要一个树,如下图所示。因为是先序遍历建立的树,所以输入时候应该是这个顺序:

123456

当然这样输入肯定不行,因为空节点也是需要0来占位的,所以输入方式应该是这样的:

1230004500600

在这里插入图片描述

在代码中测试一下:

分别输出三种遍历方式:

int main(){

    Tree *p=NULL;
    Tree *root=init(p);

    printf("ready preOrder:\n");
    preOrder(root);
    printf("\n");

    printf("ready lastOrder:\n");
    lastOrder(root);
    printf("\n");


    printf("ready midOrder:\n");
    midOrder(root);
}

按照规则输入,得到数据:

input data
1
The data is 1
 请输入左字树data
input data
2
The data is 2
 请输入左字树data
input data
3
The data is 3
 请输入左字树data
input data
0
 请输入右字树data 
input data
0
 请输入右字树data 
input data
0
 请输入右字树data 
input data
4
The data is 4
 请输入左字树data
input data
5
The data is 5
 请输入左字树data
input data
0
 请输入右字树data 
input data
0
 请输入右字树data 
input data
6
The data is 6
 请输入左字树data
input data
0
 请输入右字树data
input data
0
ready preOrder:
1  2  3  4  5  6
ready lastOrder:
3  2  5  6  4  1
ready midOrder:
3  2  1  5  4  6

对于深度,节点数目可以这样:

/*计算树的深度*/
int deep(Tree* H){
	int d1 = 0;
	int d2 = 0;
	if(NULL!=H){
		d1 = deep(H->lchild) +1;
		d2 = deep(H->rchild) +1;
	}
	return d1>=d2? d1:d2;
}

//计算叶子节点
int CountLeaf(Tree* H){
	if(NULL==H) return 0;
	if((NULL==H->lchild)&&(NULL==H->rchild)){
		return 1;
	}
	return CountLeaf(H->lchild) + CountLeaf(H->rchild);
}

关于插入删除则有许多选择,插入的位置可以是任意的。

比如插入一个7,要求以先序遍历为1234567,那么可以插入x或者y的位置。

如果要求之后插入的元素都以先序遍历的方式在后面添加,那么甚至可以让元素只作为y后的右子树。

因为树结构是一对多的形式,所以即使同一种遍历方式也有不同的插入位置。

在这里插入图片描述

标签:结点,遍历,data,二叉树,input,数据结构,root,语言版
From: https://www.cnblogs.com/cgl-dong/p/18128700

相关文章

  • 数据结构之图(c语言版)
    图是比树更复杂的结构,树是一对多的关系,图是多对多的关系。一、基本概念1、定义:图(graph)是由一些点(vertex)和这些点之间的连线(edge)所组成的;其中,点通常被成为"顶点(vertex)",而点与点之间的连线则被成为"边或弧"(edege)。通常记为,G=(V,E)。2、根据边是否有方向,将图可以划分......
  • 链表(java语言版)
    链表(Linkedlist)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。使用链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域......
  • 排序算法(c语言版)
    排序算法(c语言版)1、插入排序#include<stdio.h>//插入排序,升序voidinsertion_sort(intarr[],intlen){inti,j,key;for(i=1;i<len;i++){key=arr[i];//arr[i]为待插入的元素,保存在key中j=i-1;wh......
  • 数据结构与算法引言
    数据结构与算法引言数据结构和算法是计算机专业重要的基础课程。数据结构是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。算法简单来说就是解决问题的步骤。有了一个个数据结构和算法,我们可以编写出高质量的代码,高性能的产品。数据结构数......
  • C语言简单的数据结构:单链表的有关算法题(1)
    算法题重点在于思路,代码其实并不难,这里的每一题都提供多种思路,大家可以动手写一下,并找到更好的解题方法这里先介绍前三道题目:1.单链表相关经典算法OJ题1:移除链表元素2.单链表相关经典算法OJ题2:反转链表3.单链表相关经典算法OJ题4:链表的中间结点1.单链表相关经典算......
  • C语言简单的数据结构:单链表
    目录:1.单链表的概念及结构2.单链表的实现2.1单链表的定义、创建和打印2.11单链表的定义2.12单链表的创建2.13单链表的打印2.2单链表的头插和尾插2.21尾插2.22头插2.3单链表的头删和尾删2.31尾删2.31头删2.4单链表的查找2.5单链表指定位置的插入和删除2.51指定位置前......
  • (Java)数据结构——排序(第一节)堆排序+PTA L2-012 关于堆的判断
    前言本博客是博主用于复习数据结构以及算法的博客,如果疏忽出现错误,还望各位指正。堆排序(HeapSort)概念堆排序是一种基于堆数据结构的排序算法,其核心思想是将待排序的序列构建成一个最大堆(或最小堆),然后将堆顶元素与最后一个元素交换,再将剩余元素重新调整为最大堆(或最小堆),重复......
  • 数据结构:单链表
    一.链表的概念及结构概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。但是在逻辑结构上是顺序的。链表的结构其实就像的火车:车厢是独立存在的,且每节车厢都有车门。想象⼀下这样的场景,假设每节车厢的车门都是锁......
  • 初识--数据结构
    什么是数据结构?我们为什么要学习数据结构呢....一系列的问题就促使我们不得不了解数据结构。我们不禁要问了,学习C语言不就够了吗?为什么还要学习数据结构呢?这是因为:数据结构能够解决C语言解决不了的问题,比如:图形,树状图...要了解数据结构,就必须要知道:数据,数据项,数据元素,数据对象,......
  • 常用数据结构
    程序=数据结构+算法,数据结构是程序的骨架,而算法则是程序的灵魂常用的数据结构数组(Array):是一种线性数据结构,由相同类型的元素组成,可以通过索引访问元素。链表(LinkedList):是一种线性数据结构,由节点组成,每个节点包含数据和指向下一个节点的指针。栈(Stack):是一种后进先出(LIFO)的数......