Linux C 数据结构——二叉树

先放这张图:

可以看出,树是非线性结构;

一、树的概念

      树(tree)是n(n>=0)个节点的有限集合T,它满足两个条件:

1)有且仅有一个特定的称为根(root)的节点;

2)其余的节点可以分为m(m>=0)个互不相交的有限结合T1、T2、...、Tm,其中每一个集合又是一棵树,并成为其根的子数(Subtree)。

     树的逻辑结构:树中任何节点都可以有零个或多个直接后继节点(子节点),但至多只有一个直接前驱节点(父节点),根节点没有前驱节点,叶节点没有后继节点。

 度数:一个节点的子树的个数称为该节点的度数,一棵树的度数是指该树中节点的最大度数;

 层数:节点的层数等于父节点的层数加一,根节点的层数定义为一;

 深度:树中节点层数的最大值称为该树的高度或深度;

 

二、二叉树

       二叉树(Binary)是n(n>=0)个节点的有限集合,它或者是空集(n=0),或者是由一个根节点以及两棵互不相交的、分别称为左子树和右子树的二叉树;二叉树是有序树

二叉树的性质:

 

满二叉树:深度为k(k>=1)时2ek-1个节点的二叉树;

完全二叉树:1)只有最下面两层有度数小于2的节点;2)最下面一层的叶节点集中在最左边的若干位置上;

满二叉树是完全二叉树的一个特例。

1、二叉树的顺序存储结构

 完全二叉树节点的编号方法是从上到下,从左到右,根节点为1号节点。设完全二叉树的节点数为n,某节点编号为i :

1)当i > 1(不是根节点)时,有父节点,其父节点编号为i / 2;

2)当2 * i <= n 时,有左子树,其编号为2 * i,否则没有左子树,本身是叶节点;

3)当2 * i  + 1 < = n时,有右子树,其编号为2 * i + 1,否则没有右子树;

如何存储:

有n个节点的完全二叉树可以用有 n + 1 个元素的数组进行存储,节点号和数组下标一一对应,下标为零的元素不用。

利用以上特性,可以用下标获得节点的逻辑关系。不完全二叉树通过添加虚节点构成完全二叉树,然后用数组存储,这要浪费一些存储空间。

 通过添加非字母字符,构成完全二叉树。

2、二叉树的链式存储

1)链式存储结构:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. typedef int data_t;  
  2. typedef struct node_t //定义二叉树节点的内部结构  
  3. {  
  4.     data_t data;  
  5.     struct node_t *lchild,*rchild; //指向左孩子和右孩子的指针;  
  6. }bitree_t;  
  7. bitree_t *root; //定义指向二叉树的指针  

2)链式二叉树的创建

链式二叉树的创建要借助顺序存储,比如下面这个二叉树

 

我们需要通过添加虚节点使其成为一个完全二叉树,并用大小为n+1的数组来表示,如下

data_t a[] = {0,'a','b','c','d','e',0,'f',0,0,'g','h',0,0,'i'}; 因为节点号与数组下表是一一对应的,所以我们可以通过这个数组创建一个链式二叉树

 利用递归创建一个二叉树:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. data_t a[] = {0,'a','b','c','d','e',0,'f',0,0,'g','h',0,0,'i'};  
  2.   
  3. bitree_t *CreateBitree(int i, data_t a[], int n)  
  4. {  
  5.     bitree_t *root;  
  6.     int j;  
  7.   
  8.     root = (bitree_t *)malloc(sizeof(bitree_t));  
  9.     root->data = a[i];  
  10.   
  11.     j = 2 * i;  
  12.     if(j <= n && a[j] != '0')  
  13.     {  
  14.         root->lchild = CreateBitree(j, a, n); //创建  
  15.     }  
  16.     else  
  17.     {  
  18.         root->lchild = NULL;  
  19.     }  
  20.   
  21.     j = 2 * i + 1;  
  22.     if(j <= n && a[j] != '0')  
  23.     {  
  24.         root->rchild = CreateBitree(j, a, n);  
  25.     }  
  26.     else  
  27.     {  
  28.         root->rchild = NULL;  
  29.     }     
  30.   
  31.     return root;  
  32. }  

它的遍历顺序:

递归不论是在我们创建二叉树还是遍历二叉树都起到了很大的作用,至于递归,大家可以通过函数栈来理解,函数在执行到 root->lchild = CreateBitree(j, a, n); 这一步时,会再次调用CreateBitree()函数,这样会在栈区开辟一块空间,知道遇到终止条件才会返回,即这片内存区域会被释放,函数执行向上回收,直至该二叉树被创建,大家可以画图理解一下,有空我会补上图;


3、二叉树的遍历

    遍历:沿某条搜索路径周游二叉树,对树中的每一个节点访问一次且仅访问一次。

     由于二叉树的递归性质,遍历算法也是递归的。三种基本的遍历算法如下:

1)先序遍历:先访问树根,再访问左子树,最后访问右子树;

2)中序遍历:先访问左子树,再访问树根,最后访问右子树;

3)后序遍历:先访问左子树,再访问右子树,最后访问树根;

 

先序遍历算法:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. void PREORDER(bitree_t *r)  
  2. {  
  3.     if(r == NULL)  
  4.         return;  
  5.     printf("%c ",r->data);  
  6.     PREORDER(r->lchild);  
  7.     PREORDER(r->rchild);  
  8. }  

中序遍历算法:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. void INORDER(bitree_t *r)  
  2. {  
  3.     if(r == NULL)  
  4.         return;  
  5.     INORDER(r->lchild);  
  6.     printf("%c ",r->data);  
  7.     INORDER(r->rchild);  
  8. }  

后序遍历算法:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. void POSTORDER(bitree_t *r)  
  2. {  
  3.     if(r == NULL)  
  4.         return;  
  5.     POSTORDER(r->lchild);  
  6.     POSTORDER(r->rchild);  
  7.     printf("%c ",r->data);  
  8. }  

我们可以把程序整合一下,写个测试程序:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. int main()  
  2. {  
  3.     bitree_t *tree;  
  4.   
  5.     printf("Begin creating the tree!\n");  
  6.     tree = CreateBitree(1,a,sizeof(a)/sizeof(data_t) - 1);  
  7.     printf("Finish!\n");  
  8.   
  9.     printf("Preorder traversal:\n");  
  10.     PREORDER(tree);  
  11.   
  12.     printf("\nInorder traversal:\n");  
  13.     INORDER(tree);  
  14.   
  15.     printf("\nPostorder traversal:\n");  
  16.     POSTORDER(tree);  
  17.     printf("\n");  
  18.   
  19.     return 0;  
  20. }  

执行结果如下:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. fs@ubuntu:~/qiang/tree/bitree$ ./bitree  
  2. Begin creating the tree!  
  3. Finish!  
  4. Preorder traversal:  
  5. a b d e g h c f i   
  6. Inorder traversal:  
  7. d b g e h a c i f   
  8. Postorder traversal:  
  9. d g h e b i f c a   
  10. fs@ubuntu:~/qiang/tree/bitree$

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402397.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux C 算法——查找

所谓“查找”记为在一个含有众多的数据元素&#xff08;或记录&#xff09;的查找表中找出某个“特定的”数据&#xff0c;即在给定信息集上寻找特定信息元素的过程。 为了便于讨论&#xff0c;必须给出这个“特定的”词的确切含义。首先&#xff0c;引入一个“关键字”的概念&…

SharePoint项目中新建类库的错误处理及项目建设中遇到的问题总结

第一次SP项目总监遇到各种问题&#xff0c;以下是总结&#xff1a;问题1.创建SP项目的时候“场解决方案”跟“沙盒解决方案”是有区别的&#xff0c;具体可以看MSDN官方文档&#xff0c;这里简单摘抄如下&#xff1a;1&#xff09;场解决方案&#xff1a;承载与W3WP.exe中&…

ECharts学习(1)--简单图表的绘制

1.获取ECharts 官网 下载&#xff1a;http://echarts.baidu.com/download.html 2.在html页面中引入ECharts文件 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>ECharts练习</title><script type"text/javas…

Linux C 算法——排序

排序(Sort)是将无序的记录序列&#xff08;或称文件&#xff09;调整成有序的序列。 为了方便讨论&#xff0c;在此首先要对排序下一个确切的定义&#xff1a; 假设含有n个记录的序列为 { R1、R2、&#xff0c;。。。Rn } 其相应的关键字序列为 {K1、K2&#xff0c;。。。。Kn}…

JSON.parse 解析json字符串时,遇换行符报错

Json字符串转换成Json对象时候&#xff0c;有两种方式&#xff1a; 假设d是json字符串&#xff1a; 1&#xff0c;eval(( d ))。 2&#xff0c;JSON.parse(d)&#xff1b; 但是以上方式有隐患&#xff0c;如果Json字符串有换行的话&#xff0c;这样转换就会报错。 假如有…

文件I/O和标准I/O的区别

一、先来了解下什么是文件I/O和标准I/O&#xff1a; 文件I/O&#xff1a;文件I/O称之为不带缓存的IO&#xff08;unbuffered I/O)。不带缓存指的是每个read&#xff0c;write都调用内核中的一个系统调用。也就是一般所说的低级I/O——操作系统提供的基本IO服务&#xff0c;与os…

程序集、应用程序配置及App.config和YourSoft.exe.config .

转自&#xff1a;http://www.cnblogs.com/luminji/archive/2010/10/21/1857339.html 什么是程序集 程序集标识属性 强名称的程序集 强名称工作原理配置文件使用 DEVPATH 查找程序集指定要使用的运行库版本Appconfig和YourSoftexeconfig本章概要&#xff1a; 1&#xff1a;什么是…

[Android]在Dagger 2中使用RxJava来进行异步注入(翻译)

以下内容为原创&#xff0c;欢迎转载&#xff0c;转载请注明 来自天天博客&#xff1a;http://www.cnblogs.com/tiantianbyconan/p/6236646.html 在Dagger 2中使用RxJava来进行异步注入 原文&#xff1a;http://frogermcs.github.io/async-injection-in-dagger-2-with-rxjava 几…

关于Go语言在服务端做Restful接口和socket通信

请到我的个人博客看golang rest相关文章 http://xiaorui.cc关于Go语言在服务端做Restful接口和socket通信已经转到: http://xiaorui.cc/2014/10/25/%E5%85%B3%E4%BA%8Ego%E8%AF%AD%E8%A8%80%E5%9C%A8%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%81%9Arestful%E6%8E%A5%E5%8F%A3%E5%92%8C…

UVa 11136 - Hoax or what

题目大意&#xff1a;超市进行促销活动&#xff0c;顾客可以把账单放到一个箱子里&#xff0c;每天超市会从箱子中抽出最高消费者和最低消费者&#xff0c;最高消费者可以得到&#xff08;最高消费-最低消费&#xff09;的金钱。询问超市在n天的促销活动结束后应支付多少钱。 找…

Winfrom实现圆角设计

主要代码 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Paint(object sender, PaintEventArgs e) { Type(this, 25, 0.1); } private void…

Linux 系统应用编程——进程基础

一、Linux下多任务机制的介绍 Linux有一特性是多任务&#xff0c;多任务处理是指用户可以在同一时间内运行多个应用程序&#xff0c;每个正在执行的应用程序被称为一个任务。 多任务操作系统使用某种调度(shedule)策略&#xff08;由内核来执行&#xff09;支持多个任务并发执行…

【Python文件处理】递归批处理文件夹子目录内所有txt数据

因为有个需求&#xff0c;需要处理文件夹内所有txt文件&#xff0c;将txt里面的数据筛选&#xff0c;重新存储。 虽然手工可以做&#xff0c;但想到了python一直主张的是自动化测试&#xff0c;就想试着写一个自动化处理数据的程序。 一.分析数据格式 需要处理的数据是txt格式存…

Windows Azure 之服务总线中继服务

Windows Azure的服务总线允许在Web服务内部与外部之间做成一个公共的连接点&#xff0c;在无需更改企业防火墙或者其他安全配置的情况下连接内部和外部的服务 而使用Azure云服务的时候由于缩放的原因通过IP来制定连接也是不科学的&#xff0c;而中继服务则可以充当很好的公共连…

【qt】QT 的信号与槽机制

QT 是一个跨平台的 C GUI 应用构架&#xff0c;它提供了丰富的窗口部件集&#xff0c;具有面向对象、易于扩展、真正的组件编程等特点&#xff0c;更为引人注目的是目前 Linux 上最为流行的 KDE 桌面环境就是建立在 QT 库的基础之上。 QT 支持下列平台&#xff1a;MS/WINDOWS-9…

Linux 系统应用编程——进程间通信(上)

现在再Linux应用较多的进程间通信方式主要有以下几种&#xff1a; 1&#xff09;无名管道&#xff08;pipe&#xff09;及有名管道&#xff08;fifo&#xff09;&#xff1a;无名管道可用于具有亲缘关系进程间的通信&#xff1b;有名管道除具有管道相似的功能外&#xff0c;它还…

通过JDBK操作数据库

一、配置程序——让我们程序能找到数据库的驱动jar包1.把.jar文件复制到项目中去,整合的时候方便。2.在eclipse项目右击“构建路径”--“配置构建路径”--“库”--“添加外部jar”--找到数据库的驱动jar包--点击确定。会在左侧包资源管理器中出现“引用的库”&#xff0c;在里面…

Linux 系统应用编程——网络编程(常用命令解析)

1、telnet Telnet协议是TCP/IP协议族中的一员&#xff0c;是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet程序&#xff0c;用它连接到服务器。终端使用者可以在telnet程序中输入命令&#…

灾难 BZOJ 2815

灾难 【样例输入】 5 0 1 0 1 0 2 3 0 2 0 【样例输出】 4 1 0 0 0 题解&#xff1a; 先跑出拓扑序 我们按拓扑序建立一棵“灭绝树” 灭绝树含义是当一个点灭绝时&#xff0c;它的子树将会全部灭绝 所以答案就是点在灭绝树中的子树大小 一个点如果灭绝&#xff0c;那么需要所有…