二叉树(一)——二叉树的基本实现(数组实现和链表实现)
2014-08-05 16:14
561 查看
1.树是一种数据结构,树的一些相关的术语:
结点的度:一个结点的后继结点的个数。
树的度:树中度值最大的结点的度被称为树的度。
树的深度:树的层次数。
分支结点:度值大于0的结点,分支结点至少含有一个后继,分支结点也称为非终端结点。
叶子结点:树中的度值为0的结点。
双亲结点:树中某个结点的前驱结点,也成为父节点。
子女结点:树中某结点的后继结点。
兄弟结点:树中同一层的结点。
2.二叉树
(1)二叉树是一种特殊的树,树的度值最大为2.
(2)二叉树的表示:
A
/ \
B C
/ \ / \
D E F G
二元表示:
Binary-tree = (D, S)
D={A, B, C, D, E, F, G}
S={<A,B>, <A,C>, <B,D>, <B,E>, <C,F>, <C,G>}
3.二叉树的特点
(1)任何一棵二叉树的叶子结点总比双分支结点个数多一个。
分别设叶子结点,单分子结点,双分子结点的个数为:n0, n1, n2,则有:
n0+n1+n2 = 2n2+n1+1 ==> n0 = n2+1
2n2+n1+1:n2结点每个节点有两个叶子节点,n1结点每个结点有一个叶子结点,+1的原因是根结点不属于任何一个结点的子节点,所以根结点需要单独加上。
(2)二叉树的第i层最多有2^(i-1)个元素。
(3)一棵h层的二叉树最多有2^h - 1个元素。
4.满二叉树:h层的二叉树共有2^h - 1个元素。
完全二叉树:h层的二叉树若前h-1层是满的,最后一层是连续缺失右边的若干个结点。
对于完全二叉树存在:
(1)若结点编号为i的结点存在左子女,左子女编号为2i,若存在右子女,则右子女的结点编号为2i+1。
(2)编号为i的结点若存在双亲结点,则双亲结点的编号为i/2向下取整。
5.理想平衡二叉树:一棵h层的二叉树前h-1层是满的,最后一层的叶子结点可任意摆放。
二叉树存储的实现:
(1)顺序存储:将二叉树存储在内存中一块连续的存储单元中,数组的元素个数取决于二叉树的层数。
(2)将二叉树的每个结点的编号作为该结点在数组中的存储下标。
(3)将根节点存放在下标为1的单元里。
(4)若下标为i的单元存在左子女,则左子女的下标为2i,若存在右子女,右子女的下标为2i+1。
6.中根查找顺序
对于一个给定的二叉树,如果要对其进行遍历可以有前序遍历、中序遍历、后序遍历基本的三种遍历方式,这三种遍历方式都是相对于根而言的。比如中序遍历,就是先访问左子树,再访问根,最后访问右子树,意思就是根的访问顺序在中间。
对于一棵给定的二叉树:
中序遍历的顺序为:10, 42, 45, 55, 58, 63, 67, 70, 83, 90, 98。
从这个遍历顺序可以看出正好是一个从小到大的排过序的顺序,这是在构建二叉树的时候就可以做到的,在构建二叉树的时候,选择好根节点,比根节点小的数放到根节点的左子树,比根节点大的数放到根节点的右子树即可。
例如给出一个序列:63, 42, 45, 67, 70。
访问到63,将其作为根节点,访问到42<63则作为63的左子树,访问到45<63放到63的左子树上,而45>42所以放到42的右子树上,访问到67>63,则将67作为63的右子树,访问到70>63应该放在63的右子树上,而进一步有70>67,则70应该作为67的右子树,所以可以得到下面的二叉树:
63
/ \
42 67
\ \
45 70
7.二叉树的链式存储
结点类型:left域、data域、right域
left域:用来存放左子女的地址,若不存在左子女,left域为空。
data域:用来存放该结点的数据。
right域:用来存放右子女的地址,若不存在右子女,right域为空。
8.二叉搜索树
若树中左子女的值都小于根节点的值,右子女的值都大于根节点的值,这样的二叉树叫做二叉搜索树。
AVL树本质上还是一棵二叉搜索树(因此读者可以看到我后面的代码是继承自二叉搜索树的),它的特点是:
(1) 本身首先是一棵二叉搜索树。
(2) 带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。
9.二叉树的数组实现方式
分析:首先给定一个二叉树之后,就可以知道该二叉树的层次数h,然后创建一个2^h = 2^h - 1 + 1个元素的数组,加1的目的是因为数组的0下标是不用的,根节点存放在下标为1的单元中。所有数组中没有用到的单元,均赋值为二叉树中数值域不包含的值,这样在遍历的时候就可以将这个值作为判断的依据。
二叉树的链表实现:
结点的度:一个结点的后继结点的个数。
树的度:树中度值最大的结点的度被称为树的度。
树的深度:树的层次数。
分支结点:度值大于0的结点,分支结点至少含有一个后继,分支结点也称为非终端结点。
叶子结点:树中的度值为0的结点。
双亲结点:树中某个结点的前驱结点,也成为父节点。
子女结点:树中某结点的后继结点。
兄弟结点:树中同一层的结点。
2.二叉树
(1)二叉树是一种特殊的树,树的度值最大为2.
(2)二叉树的表示:
A
/ \
B C
/ \ / \
D E F G
二元表示:
Binary-tree = (D, S)
D={A, B, C, D, E, F, G}
S={<A,B>, <A,C>, <B,D>, <B,E>, <C,F>, <C,G>}
3.二叉树的特点
(1)任何一棵二叉树的叶子结点总比双分支结点个数多一个。
分别设叶子结点,单分子结点,双分子结点的个数为:n0, n1, n2,则有:
n0+n1+n2 = 2n2+n1+1 ==> n0 = n2+1
2n2+n1+1:n2结点每个节点有两个叶子节点,n1结点每个结点有一个叶子结点,+1的原因是根结点不属于任何一个结点的子节点,所以根结点需要单独加上。
(2)二叉树的第i层最多有2^(i-1)个元素。
(3)一棵h层的二叉树最多有2^h - 1个元素。
4.满二叉树:h层的二叉树共有2^h - 1个元素。
完全二叉树:h层的二叉树若前h-1层是满的,最后一层是连续缺失右边的若干个结点。
对于完全二叉树存在:
(1)若结点编号为i的结点存在左子女,左子女编号为2i,若存在右子女,则右子女的结点编号为2i+1。
(2)编号为i的结点若存在双亲结点,则双亲结点的编号为i/2向下取整。
5.理想平衡二叉树:一棵h层的二叉树前h-1层是满的,最后一层的叶子结点可任意摆放。
二叉树存储的实现:
(1)顺序存储:将二叉树存储在内存中一块连续的存储单元中,数组的元素个数取决于二叉树的层数。
(2)将二叉树的每个结点的编号作为该结点在数组中的存储下标。
(3)将根节点存放在下标为1的单元里。
(4)若下标为i的单元存在左子女,则左子女的下标为2i,若存在右子女,右子女的下标为2i+1。
6.中根查找顺序
对于一个给定的二叉树,如果要对其进行遍历可以有前序遍历、中序遍历、后序遍历基本的三种遍历方式,这三种遍历方式都是相对于根而言的。比如中序遍历,就是先访问左子树,再访问根,最后访问右子树,意思就是根的访问顺序在中间。
对于一棵给定的二叉树:
中序遍历的顺序为:10, 42, 45, 55, 58, 63, 67, 70, 83, 90, 98。
从这个遍历顺序可以看出正好是一个从小到大的排过序的顺序,这是在构建二叉树的时候就可以做到的,在构建二叉树的时候,选择好根节点,比根节点小的数放到根节点的左子树,比根节点大的数放到根节点的右子树即可。
例如给出一个序列:63, 42, 45, 67, 70。
访问到63,将其作为根节点,访问到42<63则作为63的左子树,访问到45<63放到63的左子树上,而45>42所以放到42的右子树上,访问到67>63,则将67作为63的右子树,访问到70>63应该放在63的右子树上,而进一步有70>67,则70应该作为67的右子树,所以可以得到下面的二叉树:
63
/ \
42 67
\ \
45 70
7.二叉树的链式存储
结点类型:left域、data域、right域
left域:用来存放左子女的地址,若不存在左子女,left域为空。
data域:用来存放该结点的数据。
right域:用来存放右子女的地址,若不存在右子女,right域为空。
8.二叉搜索树
若树中左子女的值都小于根节点的值,右子女的值都大于根节点的值,这样的二叉树叫做二叉搜索树。
AVL树本质上还是一棵二叉搜索树(因此读者可以看到我后面的代码是继承自二叉搜索树的),它的特点是:
(1) 本身首先是一棵二叉搜索树。
(2) 带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。
9.二叉树的数组实现方式
分析:首先给定一个二叉树之后,就可以知道该二叉树的层次数h,然后创建一个2^h = 2^h - 1 + 1个元素的数组,加1的目的是因为数组的0下标是不用的,根节点存放在下标为1的单元中。所有数组中没有用到的单元,均赋值为二叉树中数值域不包含的值,这样在遍历的时候就可以将这个值作为判断的依据。
#include <stdio.h> void create_btree(int list[], int bt[], int n) /*n表示list数组中元素的个数*/ { int i, order; bt[1] = list[0]; for(i = 1; i < n; i++) { order = 1; /*每次进来从根结点开始比较*/ while(bt[order] != 0) { if(list[i] < bt[order]) order *= 2; else order = order*2 + 1; } bt[order] = list[i]; } } int main() { int list[7] = {30, 18, 16, 25, 34, 7, 31}; int bt[16] = {0}; int i; create_btree(list, bt, 7); for(i = 0; i < 16; i++) /*按层输出*/ if(bt[i] != 0) printf("%4d", bt[i]); printf("\n"); return 0; }程序的输出结果:
二叉树的链表实现:
#include <stdio.h> #include <malloc.h> #define NULL 0 typedef struct tree { int data; struct tree *left, *right; }ElemBT; void create_btree(ElemBT *root, int list[], int n) /*n表示list数组中元素的个数*/ { int i; ElemBT *current, *parent, *p; for(i = 1; i < n; i++) { p = (ElemBT *)malloc(sizeof(ElemBT)); p->left = p->right = NULL; p->data = list[i]; current = root; while(current != NULL) { parent = current; if(current->data > p->data) current = current->left; else current = current->right; } if(parent->data > p->data) parent->left = p; else parent->right = p; } } int main() { int list[7] = {30, 18, 16, 25, 34, 7, 31}; ElemBT *root; root = (ElemBT *)malloc(sizeof(ElemBT)); root->data = list[0]; root->left = root->right = NULL; create_btree(root, list, 7); return 0; }
相关文章推荐
- 怎样编写一个程序,把一个有序整数数组放到二叉树中? 编写实现链表排序的一种算法。说明为什么你会选择用这样的方法?
- 链表的可变数组的实现和一些基本操作
- 用java数组实现基本链表和可自扩充的链表
- 数据结构与实现——数组、矩阵、链表、队列、栈、对象、二叉树和红黑树
- 栈和队列的基本实现(数组实现和链表实现)
- 使用C++链表来实现二叉树的存储和基本操作
- 剑指offer 01-06解答思路以及代码(顺序数组找特定数字,替换空格字符,链表反转输出,重建二叉树,两个栈实现队列效果,旋转数组最小元素)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 排序算法集:冒泡、插入、希尔、快速(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 排序算法集:冒泡、插入、希尔、快速(数组实现、链表实现)
- 链表实现动态数组C源代码
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 排序算法集:冒泡、插入、希尔、快速(数组实现、链表实现)
- Python中数组 链表 元组 字典实现类Sql多字段排序和动态函数实现
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集(数组实现、链表实现)