C语言提高篇-数据结构~二叉树

C语言提高篇-数据结构~二叉树

1、 基本概念

栈/队列/链表 - 属于逻辑结构中的线性结构
二叉树 - 属于逻辑结构中的树形结构

在计算机主中,二叉树就是指每个节点最多有两个子节点的树形结构,叫做二叉树

其中最起始的节点叫做根结点,整棵树只有一个根结点,除根结点之外,每个节点有且只有一个父节点
其中没有任何子节点的节点叫做叶子节点,叶子节点有父节点没有子节点
除了根结点和叶子节点之外,剩下的节点叫做枝节点,枝节点有父节点也有子节点
如果该二叉树中每层节点个数均达到最大值,并且每个枝节点都有两个子节点,这样的二叉树叫做满二叉树
如果该二叉树中除了最下面的一层之外,其他各层的节点树都达到了最大值,并且最下面一层的节点都连续集中在左侧,这样的二叉树叫做完全二叉树

2、基本特征

二叉树具有递归嵌套式的空间结构,因此一般采用递归的方法处理二叉树比较简单,处理方式如下:
处理(二叉树)
{
if(如果二叉树为空) 直接处理;
else
{
处理左子树; => 使用递归处理
处理根结点;
处理右子树; => 使用递归处理
}
}

3、二叉树存储结构

(1)采用顺序结构进行存储
一般来说,从上到下,从左到右依次进行存储
对于非完全二叉树来说,需要采用虚节点占位
(2)采用链式结构进行存储
一般来说,每个节点的内部有3个成员:一个用于存放数据元素本身;一个记录左子节点的地址;一个用于记录右子节点的地址,节点的数据类型如下:
typedef struct Node
{
int data;//记录数据元素本身
struct Node* left;//记录左子节点的地址
struct Node* right;//记录右子节点的地址
}Node;

4、 二叉树的基本操作

创建、增加节点、遍历、删除节点、查找节点、修改指定的节点、判空判满、销毁、计算节点的个数、以及获取根结点的元素值

5、二叉树的遍历方法

(1)先序遍历(DLR -> Data Left Right)
先遍历根结点 => 左子树 => 右子树
又叫做先根遍历
(2)中序遍历(LDR -> Left Data Right 重点)
先遍历左子树 => 根结点 => 右子树
又叫做中根遍历
(3)后序遍历(LRD -> Left Right Data)
先遍历左子树 => 右子树 => 根结点
又叫做后根遍历

6、有序二叉树

满足以下三个条件的非空二叉树,叫做有序二叉树
(1)如果左子树非空,则左子树中所有节点的值都小于等于根结点的元素值
(2)如果右子树非空,则右子树中所有节点的值都大于等于根结点的元素值
(3)左右子树也分别为有序二叉树

7、示例代码

//编程实现有序二叉树的各种操作
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

//定义节点的数据类型
typedef struct Node
{
	int data;//记录数据元素本身
	struct Node* left;//记录左子节点的地址
	struct Node* right;//记录右子节点的地址
}Node;

//定义有序二叉树的数据类型
typedef struct
{
	Node* root;//记录根结点的地址
	int cnt;//记录节点的个数
}Tree;

//实现插入一个新元素
void insert_data(Tree* pt,int data);
//实现插入的递归函数
void insert(Node** pRoot,Node* pn);
//实现遍历二叉树中所有元素
void travel_data(Tree* pt);
//中序遍历的递归函数
void travel(Node* pn);
//清空二叉树中所有的节点
void clear_data(Tree* pt);
//清空的递归函数
void clear(Node** pRoot);

int main(void)
{
	//有序二叉树的创建和初始化
	Tree tree;
	tree.root = NULL;
	tree.cnt = 0;

	insert_data(&tree,50);
	travel_data(&tree);//50
	insert_data(&tree,70);
	travel_data(&tree);//50 70
	insert_data(&tree,20);
	travel_data(&tree);//20 50 70
	insert_data(&tree,60);
	travel_data(&tree);//20 50 60 70
	
	printf("----------------------\n");
	clear_data(&tree);
	travel_data(&tree); //啥也没有
	return 0;
}

//清空的递归函数
void clear(Node** pRoot)
{
	//二叉树不为空才需要清空
	if(*pRoot != NULL)
	{
		//1.清空左子树,使用递归
		clear(&(*pRoot)->left);
		//2.清空右子树,使用递归
		clear(&(*pRoot)->right);
		//3.清空根结点
		free(*pRoot);
		*pRoot = NULL;
	}
}

//清空二叉树中所有的节点
void clear_data(Tree* pt)
{
	//调用递归函数实现清空
	clear(&pt->root);
	//节点的个数为0
	pt->cnt = 0;
}

//中序遍历的递归函数
void travel(Node* pn)
{
	//当有序二叉树中有节点时需要遍历
	if(pn != NULL)
	{
		//1.遍历左子树,使用递归
		travel(pn->left);
		//2.遍历根结点
		printf("%d ",pn->data);
		//3.遍历右子树,使用递归
		travel(pn->right);
	}
}

//实现遍历二叉树中所有元素
void travel_data(Tree* pt)
{
	printf("有序二叉树中的元素有:");
	//采用中序遍历的方法,调用递归函数
	travel(pt->root);
	printf("\n");
}

//实现插入的递归函数
void insert(Node** pRoot,Node* pn)
{
	//Node** pRoot = &pt->root;
	// Node** pRoot;  pRoot = &pt->root;
	// *pRoot = *(&pt->root) = pt->root;
	//1.如果二叉树为空,则直接插入
	if(NULL == *pRoot)
	{
		//根指针指向新结点
		*pRoot = pn;
		return;
	}
	//2.如果二叉树不为空,并且新结点元素值小于根结点元素值,则把新结点插入左子树
	else if(pn->data < (*pRoot)->data)
	{
		insert(&(*pRoot)->left,pn);
	}
	//3.如果新结点元素值大于等于根结点元素值,则把新结点插入右子树中
	else
	{
		insert(&(*pRoot)->right,pn);
	}
}

//实现插入一个新元素
void insert_data(Tree* pt,int data)
{
	//1.创建新结点和初始化 
	Node* pn = (Node*)malloc(sizeof(Node));
	if(NULL == pn)
	{
		printf("创建新结点失败\n");
		return;
	}
	pn->data = data;
	pn->left = NULL;
	pn->right = NULL;
	//2.寻找合适的位置进行插入,递归函数
	insert(&pt->root,pn);//址传递
	//3.节点元素的个数 +1
	++pt->cnt;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值