一:树的概念
树是一种非线性的数据结构,它由n(n>0)个有限节点组成的一个具有层次的关系集合。
那么为什么把它叫做树呢?
这是因为它的结构看起来就像是一颗倒挂起来的树;如下图
接下来我们就看看树节点的一些概念;
在一个n个节点的树包含一个根节点和n-1个非根节点,如上图所示,1就是该树的根节点;
而一个非根节点有且只有一个父节点,例如上图,2的父节点是1,7的父节点是3,而每一个节点具有一个或多个子节点;
且出了根节点外,每个子结 点可以分为多个不相交的子树 ;比如以2为节点,(4,8,9)和(5,10)两个子树
如下图:
关于树还有以下感念;
节点的度:一个节点含有的子树的个数称为该节点的度;如上图:2节点的度就是3,7的度是2;
非终端节点或分支节点:度不为0的节点; 如上图:1,2,3,4,5,7都是分支节点
兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:11,12是兄弟节点
树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为3
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
树的高度或深度:树中节点的最大层次; 如上图:树的高度为4
堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:9、10互为兄弟节点
节点的祖先:从根到该节点所经分支上的所有节点;如上图:1是所有节点的祖先 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是1的子孙
森林:由m(m>=0)棵互不相交的树的集合称为森林
二:树与非树
请看图一图二:他们还是树吗?
答案是不是的,因为他们违反了以下树的规定
1:子树是不相交的
2:出了根节点,其他节点有且只有一个父节点
3:一个有n个节点的树有n-条边(两个节点之间的连接线)
三:树的表示
树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,实际中树有很多种表示方式,如:双亲表 示法,孩子表示法、孩子兄弟表示法等等。阿鲤在这里这里就简单的了解其中最常用的孩子兄弟表示法
代码:
typedef int DataType;
struct Node
{
struct Node *_FirstChild; //指向第一个子节点
struct Node *_NextBother; //指向下一个兄弟节点
DataType data; //节点中的数据域
};
图解:
四:二叉树的介绍
1:二叉树的概念
一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树 的二叉树组成。
2:二叉树的特点
1. 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。
2. 二叉树的子树有左右之分,其子树的次序不能颠倒
如图:
特殊二叉树:
满二叉树:所有的父节点都有两个节点(左子节点和右子节点)
完全二叉树:最后一个节点的之前的父节点都是满节点
如图:
二叉树的性质:
1:若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2的(i-1)次方(>0)个结点
2:若规定只有根节点的二叉树的深度为1,则深度为K的二义树的最大结点数是2的K次方减1(k>=0)
3:对任何一棵二叉树,如果其叶结点个数为nO.度为2的非叶结点个数为n2,则有no=n2+ 1
4:具有n个结点的完全二叉树的深度k为log2(n+1)上取整
5:对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序
对所有节点从0开始编号,则对于序号为i的结点有有
1:若i>0,双亲序号: (i-1)/2;:
i=0为根节点编号,无双亲结点
2:若2i+1<n,左孩子序号:2i+1否则无左孩子
3. 若2i+2<n,右孩子序号2i+2否则无右孩子
五:堆的介绍
堆的概念:
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆
图解:
存储:小堆:1,5,7,6,6,9 大堆:8,7,3,4,2,0
六:堆的实现(完全二叉树的实现)
直接上代码
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int HDataType;
typedef int(*Compare) (HDataType, HDataType);
int Less(HDataType left, HDataType right)//compare of little heap
{
return left<right;
}
int Great(HDataType left, HDataType right)//compare of bit heap
{
return left>right;
}
typedef struct Heap//Heap structure
{
HDataType *_array;
int _capacity;
int _size;
Compare _comp;
}Heap;
void InitHeap(Heap *hp,Compare comp)//Initalization of heap
{
assert(hp);
hp->_array = (HDataType*)malloc(sizeof(HDataType)*3);
hp->_capacity = 3;
hp->_size = 0;
hp->_comp = comp;
}
int Swap(HDataType *left, HDataType *right)
{
int tmp = *left;
*left = *right;
*right = tmp;
}
void CheckCapacity(Heap*hp)//Inspection capacity
{
assert(hp);
if(hp->_capacity == hp->_size)
{
int newcapacity = 2*hp->_capacity;
HDataType *arr = (HDataType*)realloc(hp->_array,sizeof(HDataType)*newcapacity);
if(NULL == arr)
{
assert(0);
return;
}
hp->_array = arr;
hp->_capacity = newcapacity;
}
}
void Adjustup(HDataType *array, int child, Compare comp)//Upword adujutment
{
int parent = (child-1)/2;
while(child)
{
if(comp(array[child], array[parent]))
{
Swap(&array[child], &array[parent]);
child = parent;
parent = (child-1)/2;
}
else
{
return;
}
}
}
void InsertHeap(Heap*hp, HDataType data)//insert
{
assert(hp);
CheckCapacity(hp);//Inspection capacity
hp->_array[hp->_size++] = data;
Adjustup(hp->_array, hp->_size-1, hp->_comp);
}
void ShowHeap(Heap*hp)
{
int count = 0;
while(count < hp->_size)
{
printf("%-3d",hp->_array[count]);
count++;
}
}
int main()
{
Heap hp;
InitHeap(&hp, Great);//Initalization
InsertHeap(&hp, 1);
InsertHeap(&hp, 4);
InsertHeap(&hp, 2);
InsertHeap(&hp, 3);
InsertHeap(&hp, 9);
InsertHeap(&hp, 5);
InsertHeap(&hp, 7);
InsertHeap(&hp, 1);
InsertHeap(&hp, 10);
InsertHeap(&hp, 6);
InsertHeap(&hp, 3);
ShowHeap(&hp);
return 0;
}
图解:以小堆为例
这样多次循环插入就可以完成小堆的实现了