二叉树特性及详细例子

二叉树的性质

一般二叉树性质:

  1. 在非空二叉树的k层上,至多有2k个节点(k>=0)
  2. 高度为k的二叉树中,最多有2k+1-1个节点(k>=0)
  3. 对于任何一棵非空的二叉树,如果叶节点个数为n0,度数为2的节点个数为n2,则有: n0 = n2 + 1

完全二叉树性质:
只有最下面的两层结点度数小于2,其余各层的结点度数都等于2,并且最下面一层的结点都集中在该层最左边得若干位置上,则此二叉树称为完全二叉树。

  1. 具有n个节点的完全二叉树的高度k为[log2n]
  2. 对于具有n个节点的完全二叉树,如果按照从上(根节点)到下(叶节点)和从左到右的顺序对二叉树中的所有节点从0开始到n-1进行编号,则对于任意的下标为k的节点,有:
  • 如果k=0,则它是根节点,它没有父节点;如果k>0,则它的父节点的下标为[(i-1)/2];
  • 如果2k+1 <= n-1,则下标为k的节点的左子结点的下标为2k+1;否则,下标为k的节点没有左子结点.
  • 如果2k+2 <= n-1,则下标为k的节点的右子节点的下标为2k+2;否则,下标为k的节点没有右子节点

满二叉树性质:
任何结点或者是树叶,或有两颗非空子树。

在满二叉树中,叶节点的个数比分支节点的个数多1

扩充二叉树性质:

  1. 在扩充二叉树中,外部节点的个数比内部节点的个数多1
  2. 对任意扩充二叉树,外部路径长度E和内部路径长度I之间满足以下关系:E = I + 2n, 其中n是内部节点个数

 

二叉树的实现与周游

二叉树的顺序表示:

二叉树的顺序表示适用于完全二叉树,根据完全二叉树的第2性质,可以建立处节点之间的关系,对于一般的二叉树,可以将其扩充为完全二叉树,然后用一维数组顺序存储.

以下是程序代码:

bintree.h

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #define USED 1
  4 #define NOTUSED 0
  5 typedef int Type;
  6 
  7 // 二叉树节点结构体
  8 typedef struct treenode
  9 {
 10     int nodeIndex;
 11     // 标志是否为外部节点,如果是则为0,否则为1
 12     int isIn;
 13     // 0表示这个节点不在二叉树中,1表示在树中
 14     int isUsed;
 15     Type element;
 16 }TreeNode;
 17 
 18 // 二叉树结构体
 19 typedef struct bintree
 20 {
 21     int MAXN;
 22     int n;
 23     TreeNode *nodelist;
 24 }*Tree;
 25 
 26 // 创建最大节点为m的空二叉树
 27 Tree createBinTree(int m)
 28 {
 29     int i;
 30     Tree tree = NULL;
 31     TreeNode *nodelist = NULL;
 32     tree = malloc(sizeof(struct bintree));
 33     if (NULL != tree)
 34     {
 35         nodelist = malloc(m * sizeof(TreeNode));
 36         if (NULL != nodelist)
 37         {
 38             tree->MAXN = m;
 39             tree->n = -1;
 40             for (i = 0; i < m; i++)
 41             {
 42                 nodelist[i].isUsed = NOTUSED;
 43                 nodelist[i].nodeIndex = i;
 44             }
 45             printf("\n");    
 46             tree->nodelist = nodelist;
 47         }
 48     }
 49     return tree;
 50 }
 51 
 52 // 在二叉树末尾加入元素
 53 void inTree(Tree tree, Type x, int isIn)
 54 {
 55     void replaceTree(Tree, Type, int, int);
 56     if (tree->n + 1 < tree->MAXN)
 57     {
 58         replaceTree(tree, x, tree->n + 1, isIn);
 59         tree->n = tree->n + 1;
 60     }
 61     return;
 62 }
 63 
 64 // 替换二叉树中指定下标的元素
 65 void replaceTree(Tree tree, Type x, int index, int isIn)
 66 {
 67     if (tree->n == -1 || (index >= 0 && index <= tree->n + 1))
 68     {
 69         tree->nodelist[index].element = x;
 70         tree->nodelist[index].isIn = isIn;
 71         tree->nodelist[index].isUsed = USED;
 72     }
 73     return;
 74 }
 75 
 76 // 得到指定下标的元素
 77 Type getNode(Tree tree, int index)
 78 {
 79     int re;
 80     if (index >= 0 && index <= tree->n)
 81         re = tree->nodelist[index].element;
 82     return re;
 83 }
 84 
 85 // 得到父节点的元素下标
 86 int parent(Tree tree, int child)
 87 {
 88     if (child < 0 || child > tree->n)
 89         return -1;
 90     else
 91         return (child - 1) / 2;
 92 }
 93 
 94 // 得到右子节点的元素下标
 95 int rightChild(Tree tree, int parent)
 96 {
 97     if (parent < 0 || parent > tree->n)
 98         return -1;
 99     else
100         return 2 * parent + 2;
101 }
102 
103 // 得到左子节点的元素下标
104 int leftChild(Tree tree, int parent)
105 {
106     if (parent < 0 || parent > tree->n)
107         return -1;
108     else
109         return 2 * parent + 1;
110 }

 

这里用的是非递归的周游方法,所以要用到栈,一下是自定义的栈.

stack.h

 1 #include "bintree.h"
 2 typedef TreeNode DataType;
 3 
 4 typedef struct mystack
 5 {
 6     //数组最大长度
 7     int MAXN;
 8     //指定栈顶位置
 9     int index;
10     DataType *ele;
11     
12 }*MyStack, Stack;
13 
14 
15 //创建一个空栈
16 MyStack createStack(int num)
17 {
18     MyStack stack = NULL;
19     stack = malloc(sizeof(Stack));
20     if(stack != NULL)
21     {
22         stack->ele = malloc(sizeof(DataType) * num);
23         if(stack ->ele != NULL)
24         {
25             stack ->MAXN = num;
26             stack ->index = -1;
27         }
28     }
29     return stack;
30 }
31 
32 //判断栈是否为空
33 int isEmptyStack(MyStack stack)
34 {
35     return stack ->index == -1;
36 }
37 
38 //元素入栈,如果栈已经满则返回0,否则返回1
39 int push(MyStack stack, DataType x)
40 {
41     int index = stack ->index + 1;
42     if(index >= stack ->MAXN)
43         return 0;
44     else
45     {
46         stack ->ele[index] = x;
47         stack ->index = index;    
48         return 1;
49     }
50 }
51 
52 //元素出栈,如果栈已经为空返回0,否则返回1
53 int pop(MyStack stack)
54 {
55     if(isEmptyStack(stack))
56         return 0;
57     else
58     {
59         stack ->index--;
60         return 1;
61     }
62 }
63 
64 //取栈顶元素
65 DataType top(MyStack stack)
66 {
67     DataType get;
68     if(!isEmptyStack(stack))
69         get = stack ->ele[stack ->index];
70     return get;
71 }

 

bintree.c

  1 #include "stack.h"
  2 
  3 //访问节点信息
  4 int visit(TreeNode node)
  5 {
  6     printf(" %d", node.element);
  7     return node.nodeIndex;
  8 }
  9 
 10 //先根次序周游
 11 void preOrder(Tree tree, MyStack stack)
 12 {
 13     int index = 0;
 14     TreeNode node;
 15     if(!tree->nodelist[index].isUsed)
 16         return;
 17     push(stack,tree->nodelist[index]);
 18     while(!isEmptyStack(stack))
 19     {
 20         node = top(stack);
 21         pop(stack);
 22         if(node.isUsed == USED)
 23         {
 24             index = visit(node);
 25             push(stack,tree->nodelist[rightChild(tree, index)]);
 26             push(stack,tree->nodelist[leftChild(tree, index)]);
 27         }
 28         
 29     }
 30 }
 31 
 32 //中根次序周游
 33 void inOrder(Tree tree, MyStack stack)
 34 {
 35     int index = 0;
 36     TreeNode node;
 37     if(tree->nodelist[index].isUsed == NOTUSED)
 38         return;
 39     do 
 40     {
 41         while(tree->nodelist[index].isUsed == USED)
 42         {
 43             push(stack,tree->nodelist[index]);
 44             index = leftChild(tree, index);
 45         }
 46         node = top(stack);
 47         pop(stack);
 48         index = visit(node);
 49         index = rightChild(tree,index);
 50     } while(tree->nodelist[index].isUsed == USED || !isEmptyStack(stack));
 51         
 52 }
 53 
 54 //后根次序周游
 55 void postOrder(Tree tree, MyStack stack)
 56 {
 57     int index = 0, rightIndex;
 58     TreeNode node;
 59     if(tree->nodelist[index].isUsed == NOTUSED)
 60         return;
 61     while(tree->nodelist[index].isUsed == USED || !isEmptyStack(stack))
 62     {
 63         while(tree->nodelist[index].isUsed == USED)
 64         {
 65             push(stack,tree->nodelist[index]); 
 66             rightIndex = rightChild(tree, index);
 67             index = leftChild(tree ,index);
 68             if(tree->nodelist[index].isUsed == NOTUSED)
 69                 index = rightIndex;
 70         }
 71         node = top(stack);
 72         pop(stack);
 73         index = visit(node);
 74         //如果栈不为空,且从左子树退回,进入到右子树遍历
 75         if(!isEmptyStack(stack) && index == leftChild(tree,top(stack).nodeIndex))
 76             index = rightChild(tree,top(stack).nodeIndex);
 77         else tree->nodelist[index].isUsed = NOTUSED;
 78     }
 79     
 80 }
 81 
 82 int main()
 83 {
 84     int m = 0, isIn = 1, j, buffer = 0;
 85     Tree tree = NULL;
 86     MyStack stack = NULL;
 87 
 88     printf("请输入节点个数:");
 89     scanf("%d",&m);
 90     tree = createBinTree(m);
 91     stack = createStack(m);
 92     printf("请输入%d个数字:",m);
 93     //将0到5六个元素依次放入二叉树中
 94     for(j = 0; j < m; j++)
 95     {
 96         scanf(" %d", &buffer);
 97         inTree(tree, buffer, isIn);
 98     }
 99 
100     printf("先根次序周游结果为:");
101     preOrder(tree,stack);
102     printf("\n");
103 
104     printf("中根次序周游结果为:");
105     inOrder(tree, stack);
106     printf("\n");
107 
108     printf("后根次序周游结果为:");
109     postOrder(tree, stack);
110     printf("\n");
111 
112     return 1;
113 }

 

按图示二叉树输出:

输出结果为:

 

二叉树连接表示:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 typedef int DataType;
  4 typedef struct treenode *TreeNode;
  5 typedef struct treenode *BinTree;
  6 
  7 struct treenode
  8 {
  9     DataType element;
 10     TreeNode llink;
 11     TreeNode rlink;
 12 };
 13 
 14 BinTree createBinTree(DataType x)
 15 {
 16     BinTree tree = NULL;
 17     tree = malloc(sizeof(struct treenode));
 18     tree->element = x;
 19     return tree;
 20 }
 21 
 22 BinTree addToLeft(BinTree t, DataType x)
 23 {
 24     TreeNode node = NULL;
 25     node = malloc(sizeof(struct treenode));
 26     if (node != NULL)
 27         node->element = x;
 28     t -> llink = node;
 29     return node;
 30 }
 31 
 32 BinTree addToRight(BinTree t, DataType x)
 33 {
 34     TreeNode node = NULL;
 35     node = malloc(sizeof(struct treenode));
 36     if (node != NULL)
 37         node->element = x;
 38     t-> rlink = node;
 39     return node;
 40 }
 41 
 42 void visitRoot(BinTree tree)
 43 {
 44     printf("%d ", tree->element);
 45 }
 46 
 47 BinTree leftChild(BinTree tree)
 48 {
 49     return tree->llink;
 50 }
 51 
 52 BinTree rightChild(BinTree tree)
 53 {
 54     return tree->rlink;
 55 }
 56 //用递归方法
 57 //先根周游
 58 void preOrder(BinTree tree)
 59 {
 60     if(tree == NULL)
 61         return;
 62     visitRoot(tree);
 63     preOrder(leftChild(tree));
 64     preOrder(rightChild(tree));
 65 }
 66 
 67 //中根周游
 68 void inOrder(BinTree tree)
 69 {
 70     if(NULL == tree)
 71         return;
 72     inOrder(leftChild(tree));
 73     visitRoot(tree);
 74     inOrder(rightChild(tree));
 75 }
 76 
 77 //后根周游
 78 void postOrder(BinTree tree)
 79 {
 80     if(NULL == tree)
 81         return;
 82     postOrder(leftChild(tree));
 83     postOrder(rightChild(tree));
 84     visitRoot(tree);
 85 }
 86 
 87 int main()
 88 {
 89     BinTree left, right;
 90     BinTree tree = createBinTree(5);
 91     left = addToLeft(tree, 4);
 92     right = addToRight(tree, 3);
 93     addToLeft(left, 8);
 94     addToRight(left, 7);
 95     addToLeft(right, 6);
 96     
 97     printf("先根周游次序:");
 98     preOrder(tree);
 99     printf("\n");
100     printf("中根周游次序:");
101     inOrder(tree);
102     printf("\n");
103     printf("后根周游算法:");
104     postOrder(tree);
105     printf("\n");
106     return 1;
107 }

 

 

转载于:https://www.cnblogs.com/hanyuan/archive/2012/05/10/bintree.html

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

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

相关文章

创建 Spring容器的三种方式

一、src路径下打包完在war包的classes层级下 1、Spring容器创建的三种方式 创建Bean容器之后创建对象&#xff1a; 其中第三种使用的是BeanFactory对象 2、spring通过配置文件用容器创建对象的原理 转载于:https://www.cnblogs.com/wmqiang/p/11537638.html

yii使用寻呼功能

CDbCriteria这是类包使用&#xff0c;包是yii自带专门用来处理类似分类这种功能的。而我们使用yii框架然后调用这种方法会起到事半功倍的效果&#xff0c;会发现使用这个可以节省非常多的时间。让你高速的使用PHP中分页的功能。 还要使用的一个类包就是CPagination&#xff0c;…

VTK:一个面向对象的可视化类库(zz)

VTK&#xff1a;一个面向对象的可视化类库(zz) &#xff08;高隽 黄伟 合肥工业大学计算机与信息学院 合肥 230009&#xff09; 摘要 Visualization Toolkit 是一个面向对象的可视化类库&#xff0c;它为从事可视化应用程序开发的广大科研工作者提供直接的技术支持。VTK…

装配Bean的三种方式

一、装配Bean就是在xml写一个Bean标签&#xff1b;装配完Bean,还需要读取xml配置文件创建Spring容器来创建对象&#xff1b; 1、new 实现类方式 正常的三种创建Bean容器的方法都可以根据装配的Bean创建的Bean对象&#xff1b; 2、静态工厂模式方式 其中&#xff0c;静态工厂方式…

通用权限管理系统组件 (GPM - General Permissions Manager) 权限管理以前我们都是自己开发,可是到下一个系统又不适用,又改,加上人员流动大,管理很混乱...

权限管理以前我们都是自己开发&#xff0c;可是到下一个系统又不适用&#xff0c;又改&#xff0c;加上人员流动大&#xff0c;管理很混乱 Ψ吉日嘎拉 采用通用权限管理系统&#xff0c;这些烦恼就少了很多了&#xff0c;很固定&#xff0c;很稳定。 权限管理系统是否支持按组织…

Mahout 介绍

1.Hbasek-means (G级别) 2.k-meansmr (T级别)1. 2.canopy 2.贝叶斯算法 决策&#xff0c;分类&#xff0c;文档分类3.推荐系统 4.图书推荐系统 1.需求 付完款的用户90%都要回到购物车看看自己买的东西是否少买/多买 猜你喜欢 购买组合 内部推荐系统测试jps查询 转载于:https:/…

Android游戏开发系统控件-CheckBox

Android游戏开发系统控件-CheckBox 2012/5/11 星期五 CheckBox是Android系统最普通的UI控件&#xff0c;继承了Button按钮 下面通过一个实例来学习 作者&#xff1a;wwj 功能&#xff1a;实现复选框的功能 创建项目“CheckBoxProject” 运行项目效果截图&#xff1a; 代码实现&…

改变Fragment的默认动画

FragmentTransaction ft getFragmentManager().beginTransaction(); //设置进入退出动画 ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);DetailsFragment newFragment DetailsFragment.newInstance();ft.replace(R.id.details_fragment_container, …

Android从无知到有知——NO.7

的ip拨号器在监听外拨电话时用的是系统提供的广播事件。而有些时候我们须要自己设定广播事件来满足特定的须要。Ok&#xff0c;今天整一下自己定义广播事件&#xff0c;我们用一个状态监測模块向一个3G模块发送报警信息来实现这一想法。 先定义一个3g模块用来接收特定的广播&am…

Flex 学习随笔 ---- 玩 Chart

上次好象写了Flex通过web服务访问数据库&#xff0c;并绑定一个简单的Chart. 在Flex Builder 3 里&#xff0c;有很多Chart &#xff0c;我好象只会一个ColumnChart。不过其他的也差不多。 来个简单的。上代码才是王道。。 Code<mx:Panel layout"absolute" right&…

浅析拯救小矮人的 nlogn 算法及其证明

浅析拯救小矮人的 nlogn 算法及其证明 题型简介&#xff1a; 有 $ n $ 个人&#xff0c;第 $ i $ 个人身高 $ a_i $ 手长 $ b_i $ &#xff0c;他们为了从一个高为 $ H $ 的洞中出去&#xff0c;决定搭人梯。如果一个人和他下面的人的身高之和加上他的手长可以达到洞的高度&…

Android Material Design TabLayout属性app:tabMode和app: tabGravity

Android Material Design TabLayout属性app:tabMode和app: tabGravity Android Material Design 中的TabLayout有两个比较有用的属性 app:tabMode、app:tabGravity&#xff0c; &#xff08;1&#xff09;app:tabMode有两个值&#xff1a;fixed和scrollable。 &#xff08;2&am…

unity混音

前言在游戏中&#xff0c;通常我们需要控制整个游戏的主音量&#xff08;全局音量&#xff09;&#xff0c;并且单独控制背景音乐和其他音效&#xff08;攻击、爆炸之类&#xff09;的音量&#xff0c;这时我们可以用Audio Mixer来解决。 如果文章中有哪些地方写的不对&#xf…

一个较完整的关键字过滤解决方案(上)

如果您希望看到关键字过滤算法的话那么可能就要失望了。博客园中已经有不少关于此类算法的文章&#xff08;例如这里和这里&#xff09;&#xff0c;虽然可能无法直接满足特定需求&#xff0c;但是已经足够作为参考使用。而本文的目的&#xff0c;是给出一个较为完整的关键字过…

【转】Thunderbird中配置签名

原文网址&#xff1a;https://support.mozilla.org/zh-CN/kb/Thunderbird%E4%B8%AD%E9%85%8D%E7%BD%AE%E7%AD%BE%E5%90%8D “签名”是一块自动附加到每个您发出的消息的文字&#xff08;包括新消息和对收到消息的回复&#xff09;。他们通常用来提供与每个消息有关的附加联系信…

依赖注入Bean属性——手动装配Bean

一、构造方法注入 其中&#xff0c;可以根据不同的参数列表调用不同的重载的构造方法&#xff1b; 其中&#xff0c;基本数据类型没有包&#xff0c;引用类型都有包路径&#xff0c;基本类型对应封装类&#xff1b; 二、通过property标签调用类的set方法注入 三、通过p命名空间…

ADO.NET数据库

ASP.NET提供了ADO.NET技术&#xff0c;它是ASP.NET应用程序与数据库进行交互的一种技术。 ADO.NET技术把对数据库的操作分为几个步骤&#xff0c;并为每个步骤提供对象来封装操作过程&#xff0c;从而使对数据库的操作变得简单易行。 ADO.NET组件通过以下两个主要的组件将数据访…

十天学会ASP.Net——(2)

2.Web控件 1&#xff09;WebControl基类属性 参考http://msdn.microsoft.com/zh-cn/library/7zt8s89c 2&#xff09;Form控件&#xff08;很简单&#xff09; 应用&#xff1a;实现如下效果 <form id"form1" runat"server"> <div> 班级:<br…

Spring表达式

一、SpEL 其中&#xff0c;直接写也可以赋值&#xff0c;‘ ’ 单引号引起来后成为一个字符串对象&#xff0c;可以调用String的方法&#xff1b; 二、引用另外一个bean 装配这个类的bean&#xff1a; 1、第一种方法&#xff0c;property标签中使用bean引用 2、使用Spring表达…

集合属性注入值

一、集合注入&#xff0c;装配bean的时候&#xff0c;即在xml中添加bean的时候 1、List集合 2、set集合&#xff0c;无序&#xff0c;即无索引&#xff0c;所以也无重复&#xff0c; 3、map key-value键值对双列集合&#xff0c;内置接口Entry 4、Properties集合&#xff0c;可…