数据结构之---二叉树C实现
学过数据结构的都知道树,那么什么是树?
1、每个节点最多有两个子节点的树形结构
2、其中起始节点叫做根节点,除了根节点之外,每个节点有且只有一个父节点
3、没有任何子节点的节点 叫做叶子节点,除了叶子节点之外,每个节点都可以有两个子节点
4、除了根节点和叶子节点之外,剩下的节点叫枝节点,枝节点有父节点也有子节点
5、二叉树中每层节点均达到最大值,并且除了叶子节点之外每个节点都有两个子节点,叫做满二叉树
6、二叉树中除了最后一层之外,每层节点数均达到最大值,并且最后一层的节点连续集中在左边,叫完全二叉树
对于二叉树的处理采用递归的方法:
处理(二叉树)
{
if(二叉树为空) 直接处理;
else
{
处理根节点;
处理左子树;=> 递归
处理右子树;=> 递归
}
}
二叉树的存储结构
(1)顺序存储结构
从上到下,从左到右,依次存储每个节点
(2)链式存储结构
每个节点中除了存储数据元素本身之外,还需要两指针
如:
typedef struct Node { int data;//数据内容 struct Node* left;//指向左子树 struct Node* right;//指向右子树 }Node;
遍历方式
(1)先序遍历 =>
根 左子树 右子树
(2)中序遍历 =>
左子树 根 右子树
(3)后序遍历 =>
左子树 右子树 根
有序二叉树
左子树节点 <=
根节点 <= 右子树节点
主要搜索和查找数据的功能中
接下来我们来看看二叉树的各类操作的实现:
//实现有序二叉树的各种操作 #include <stdio.h> #include <stdlib.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* pRoot); //实现创建新节点 Node* create_node(int data); //实现清空树中的所有节点 void clear_data(Tree* pt); //实现清空的递归函数 void clear(Node** pRoot); //实现查找一个指定的节点 Node** find_data(Tree* pt,int data); //查找的递归函数 Node** find(Node** pRoot,int data); //实现删除指定的节点 void del_data(Tree* pt,int data); //修改指定元素的操作 void modify(Tree* pt,int data,int new_data); //判断二叉树是否为空 int empty(Tree* pt); //判断二叉树是否为满 int full(Tree* pt); //计算二叉树中节点的个数 int size(Tree* pt); //获取根节点的元素值 int get_root(Tree* pt); 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);//20 50 60 70 del_data(&tree,50); travel_data(&tree);//20 60 70 del_data(&tree,30);//删除失败 travel_data(&tree);//20 60 70 del_data(&tree,20); travel_data(&tree);//60 70 printf("--------------------\n"); modify(&tree,10,20);//插入20 travel_data(&tree);//20 60 70 printf("二叉树中根节点的元素是:%d\n",get_root(&tree));//70 printf("二叉树中节点的个数是:%d\n",size(&tree));//3 printf("%s\n",empty(&tree)?"二叉树为空":"二叉树不为空"); printf("%s\n",full(&tree)?"二叉树已满":"二叉树没有满"); return 0; } //修改指定元素的操作 //旧元素不存在时,直接插入新元素即可 void modify(Tree* pt,int data,int new_data) { //1.删除旧元素 del_data(pt,data); //2.插入新元素 insert_data(pt,new_data); } //判断二叉树是否为空 int empty(Tree* pt) { return NULL == pt->root; } //判断二叉树是否为满 int full(Tree* pt) { return 0; } //计算二叉树中节点的个数 int size(Tree* pt) { return pt->cnt; } //获取根节点的元素值 int get_root(Tree* pt) { if(empty(pt)) { return -1;//表示失败(以后讲到) } return pt->root->data; } //实现删除指定的节点 void del_data(Tree* pt,int data) { //1.查找目标元素所在节点的地址 Node** pp = find_data(pt,data); //2.判断查找失败情况,不需要删除 if(NULL == *pp) { printf("目标元素不存在,删除失败\n"); return; } //3.合并左右子树,左子树插入到右子树中 if((*pp)->left != NULL) { //左子树不为空时,需要插入到右子树中 insert(&(*pp)->right,(*pp)->left); } //4.寻找指针记录要删除的节点地址 Node* q = *pp; //5.将原来指向要删除节点的指针 重新指向 合并之后的右子树 *pp = (*pp)->right; //6.删除目标元素所在的节点 free(q); q = NULL; //7.节点个数减1 pt->cnt--; } //查找的递归函数 Node** find(Node** pRoot,int data) { //1.判断二叉树是否为空,为空直接返回 if(NULL == *pRoot) { return pRoot;//&pt->root; } //2.比较根节点元素和目标元素的大小,如果相等,直接返回 if(data == (*pRoot)->data) { return pRoot;//&pt->root; } //3.若目标元素小于根节点元素值,左子树查找 else if(data < (*pRoot)->data) { return find(&(*pRoot)->left,data); } //4.若目标元素大于根节点元素,去右子树查找 else { return find(&(*pRoot)->right,data); } } //实现查找一个指定的节点 //返回 指向目标元素所在节点的指针 的地址 Node** find_data(Tree* pt,int data) { //调用递归函数实现查找 return find(&pt->root,data); } //实现清空的递归函数 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); //二叉树的节点个数清零 pt->cnt = 0; } //实现创建新节点 Node* create_node(int data) { Node* pn = (Node*)malloc(sizeof(Node)); pn->data = data; pn->left = NULL; pn->right = NULL; return pn; } //遍历的递归函数 void travel(Node* pRoot) { //判断二叉树不为空时才需要遍历 if(pRoot != NULL) { //1.遍历左子树 travel(pRoot->left); //2.遍历根节点 printf("%d ",pRoot->data); //3.遍历右子树 travel(pRoot->right); } } //采用中序遍历方法进行遍历 void travel_data(Tree* pt) { //调用递归函数进行遍历 travel(pt->root); //打印换行 printf("\n"); } //插入新节点的递归函数 void insert(Node** pRoot,Node* pn) { //1.判断二叉树是否为空,如果为空则让根节点指针直接指向新节点 if(NULL == *pRoot) { *pRoot = pn; return; } //2.如果二叉树非空,比较根节点和新节点大小 //2.1 如果根节点大于新节点,插入左子树 if((*pRoot)->data > pn->data) { insert(&(*pRoot)->left,pn); } //2.2 如果根节点小于等于新节点,插入右子树 else { insert(&(*pRoot)->right,pn); } } //实现向有序二叉树中插入新节点的操作 void insert_data(Tree* pt,int data) { //1.创建新节点,进行初始化 create_node //Node* pn = (Node*)malloc(sizeof(Node)); //pn->data = data; //pn->left = NULL; //pn->right = NULL; //2.插入新节点到二叉树中,调用递归函数 insert(&pt->root,create_node(data)); //3.二叉树中节点个数加1 pt->cnt++; }
运行结果:
数据结构之---二叉树C实现的更多相关文章
- python数据结构之二叉树的统计与转换实例
python数据结构之二叉树的统计与转换实例 这篇文章主要介绍了python数据结构之二叉树的统计与转换实例,例如统计二叉树的叶子.分支节点,以及二叉树的左右两树互换等,需要的朋友可以参考下 一.获取 ...
- python数据结构之二叉树的实现
树的定义 树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构,很象自然界中的树那样.树结构在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都可用树形 ...
- Python数据结构之二叉树
本来打算一个学期分别用C++.Python.Java实现数据结构,看来要提前了 这个是Python版本,我写的数据结构尽量保持灵活性,本文bt1是一般的插入法建立二叉树结构,bt2就是可以任意输入,至 ...
- C++数据结构之二叉树
之前打算编算法类的程序,但是搞了几次英雄会后,觉得作为一个还在学习阶段的学生,实在是太浪费时间了,并不是没意义,而是我的基础还不牢固啊.所以转变了思路,这个学期打算分别用C++.Python.Java ...
- java数据结构之二叉树的实现
java二叉树的简单实现,可以简单实现深度为n的二叉树的建立,二叉树的前序遍历,中序遍历,后序遍历输出. /** *数据结构之树的实现 *2016/4/29 * **/ package cn.Link ...
- 数据结构之二叉树(BinaryTree)
导读 二叉树是一种很常见的数据结构,但要注意的是,二叉树并不是树的特殊情况,二叉树与树是两种不一样的数据结构. 目录 一. 二叉树的定义 二.二叉树为何不是特殊的树 三.二叉树的五种基本形态 四.二叉 ...
- 算法与数据结构(三) 二叉树的遍历及其线索化(Swift版)
前面两篇博客介绍了线性表的顺序存储与链式存储以及对应的操作,并且还聊了栈与队列的相关内容.本篇博客我们就继续聊数据结构的相关东西,并且所涉及的相关Demo依然使用面向对象语言Swift来表示.本篇博客 ...
- 一步一步写数据结构(二叉树的建立和遍历,c++)
简述: 二叉树是十分重要的数据结构,主要用来存放数据,并且方便查找等操作,在很多地方有广泛的应用. 二叉树有很多种类,比如线索二叉树,二叉排序树,平衡二叉树等,本文写的是最基础最简单的二叉树. 思路: ...
- js数据结构之二叉树的详细实现方法
数据结构中,二叉树的使用频率非常高,这得益于二叉树优秀的性能. 二叉树是非线性的数据结构,用以存储带有层级的数据,其用于查找的删除的性能非常高. 二叉树 数据结构的实现方法如下: function N ...
随机推荐
- x264源代码简单分析:x264_slice_write()
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- P2P系统,一致性哈希和DHT
数据网格产品经常会使用P2P进行通信,借此机会系统地学习一下P2P网络和其资源搜索策略. 1 P2P网络架构 谈到P2P就涉及到一个概念:Overlay Network(覆盖网络).所谓覆盖网络是应用 ...
- Linux日志管理高级进阶:实例详解syslog
syslog已被许多日志函数采纳,它用在许多保护措施中,任何程序都可以通过syslog记录事件.syslog可以记录系统事件,可以写到一个文件或设备中,或给用户发送一个信息.它能记录本地事件或通过网络 ...
- Android开源框架ViewPagerIndicator的基本使用
转载本博客请注明出处:点击打开链接 http://blog.csdn.net/qq_32059827/article/details/52495647 很多新闻资讯类的app都有一些共性,那就是 ...
- 非ROOT实现静默安装的一些思考与体会,AIDL获取IPackageManager,反射ServiceManager,系统签名
非ROOT实现静默安装的一些思考与体会,AIDL获取IPackageManager,反射ServiceManager,系统签名 最近自家的系统要做一个升级服务,里面有三个功能,第一个是系统升级,也就是 ...
- Libgdx教程目录
Libgdx教程 Note:本教程用的Libgdx 1.9.2版本,在教程更新完毕之前应该不会更新版本.之前的博客中也发表过Libgdx的内容,不过当时都从别人那里拷贝的,因此现在想做一个Libgdx ...
- iOS下JS与OC互相调用(一)--UIWebView 拦截URL
最近准备把之前用UIWebView实现的JS与原生相互调用功能,用WKWebView来替换.顺便搜索整理了一下JS 与OC 交互的方式,非常之多啊.目前我已知的JS 与 OC 交互的处理方式: * 1 ...
- SSH深度历险(四) Maven初步学习
这几天接触这个词,很多遍了,只是浅显的体会到它在GXPT中的好处,功能之强大,又通过网络查询了资料进一步的认识学习了,和大家分享. Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理 ...
- Linux内核编译时会遇到的问题--缺少mkimage
由于各大平台所带的内核不同,所以编译方式也不同,但方法都是大同小异. 但是,编译内核有时候会提示缺少mkimage这个命令,如何解决? 供应商提供内核的同时也会提供其它的一些,比如Uboot,root ...
- UNIX网络编程——TCP长连接与短连接的区别
一.TCP短连接 我们模拟一下TCP短连接的情况,client向server发起连接请求,server接到请求,然后双方建立连接.client向server发送消息,server回应client,然后 ...