您的位置:首页 > 理论基础 > 数据结构算法

【数据结构---26】树以及二叉树的基本概念

2019-05-23 22:54 1441 查看

文章目录

树的概念:

一种非线性的数据结构,它是由n个(n>=0)有限节点组成的一个具有层次关系的集合

与树相关的基本概念:

深度:树中节点的最大层次

双亲:若一个节点含有子节点,则这个节点是这个子节点的双亲节点

子节点:一个节点含有的子树的根节点被称为这个节点的子节点

兄弟:具有相同双亲节点的被称为兄弟节点

叶节点:度为0的节点被称为叶节点

树的表示方式:

孩子表示法,双亲表示法,孩子双亲表示法,孩子兄弟表示法

二叉树:

空树,根+根的左子树+根的右子树

特殊的二叉树:

满二叉树:每一层的节点数都达到最大值,这个二叉树就是满二叉树

完全二叉树:从上之下从左至右一次填满的二叉树,不可能存在只有右孩子没有左孩子

二叉树的五条特性:

1.若规定根节点的层次为1,则一颗非空二叉树的第i层最多有2^(i-1)个节点

2.若规定只有根节点的二叉树深度为1,则深度为k的二叉树最大节点数是2^k-1

3.对任意一颗二叉树,如果其叶节点个数为n0,度为2的非叶节点个数为n2,则有n0=n2+1

4.具有n个节点的完全二叉树的深度k为log2(n+1)向上取整

5.对于有n个节点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0进行编号

则对于序号为i的节点有:

<1>.若i>0,双亲序号:(i-1)/2i=0,i为根节点编号,无双亲节点

<2>.若2i+1<n,左孩子序号:2i+1,否则无左孩子

<3>.若2i+2<n,右孩子序号:2i+2,否则无右孩子

二叉树的存储:

顺序结构:完全二叉树(基本不会增加删除)

链式结构:通过指针来表示节点与其孩子及双亲之间的关系,常用孩子表示法,孩子双亲表示法

二叉树顺序存储: 堆(是一棵完全二叉树),堆中的元素存储到一维数组中,对于任意节点如果该节点中小于(大于)其左右孩子,就把这种结构称为小堆(大堆)

堆的特性: 堆顶元素一定是堆中所有元素最大的(最小的)

堆序堆的实现:

结构类似于顺序表

调整堆序:

int child=parent*2+1;默认child标记parent的左孩子

因为完全二叉树某个节点只有一个孩子,该孩子一定是其双亲的左孩子

向下调整:(调整的是以parent为根的子树)

找出较小的孩子---左右孩子比较(左右孩子必须都存在,child+1<size)

左孩子比右孩子大的话,child+=1

双亲比较小的孩子大的话,交换双亲和孩子的顺序

更新parent=child;chil=parent*2+1;

2i+1已经大于size(数组节点个数),说明孩子不存在

创建堆的时间复杂度Nlog2(N)

堆的删除操作:

堆里没有元素不删除

有的话就删除堆顶元素-----

堆顶元素和末尾元素交换

size的值要更新-----对堆顶元素进行向下调整

AdjustDown(heapdatatype*array,heapdatatype*size,0)

堆的插入操作:

考虑空间是否放得下-----插入之后需要调整堆序-----向上调整,传的参数是孩子

孩子小于双亲,需要交换-----child=parent;parent=(child-1)/2;

循环终止条件child!=0;

AdjusUp(hp->array,hp->size,hp->size-1);

扩容:

申请新空间-----拷贝元素

用堆的思想进行排序

降序是大堆,升序是小堆-----HeapSort(array,sizeof(array)/sizeof(array[0]))

TOP K问题(海量数据)

冒泡和堆排的话必须一次拿到所有的数据-----100亿数据需要40G内存空间

直接遍历K次,需要多次IO,性能太差-----堆-----取前K个数据,建小堆

从剩余的N-K个数据一次与堆顶的元素进行比较,然后选择是否替换

比堆顶元素大的替换掉,最后堆里的K个元素都是最大的

堆的应用需要做到正背如流!!!!!!!!

二叉树的链式存储方式

二叉树的遍历: 按照某种特定的规则,对二叉树中的每一个节点进行相应的操作,并且每个节点只能操作一次

前序遍历:	根--->根的左子树--->根的右子树

中序遍历:	根的左子树--->根--->根的右子树

后序遍历:	根的左子树--->根的右子树--->根

递归遍历,先遍历根,然后继续调用,传的参数是root根节点的左子树,然后继续调用,传root的右子树

求二叉树的节点个数:

(根据二叉树的概念)	空树---0个	非空就递归求解
int Getsize(Node*Root)
{
if(Root==NULL)
{
return 0;
}
return Getsize(Root->left)+Getsize(Root->right)+1;
}

二叉树的创建方式:

索引必须给地址,因为要把索引的值带出函数外!!!!!!

创建链式二叉树—>递归跳出条件(*index<size)—>先创建根节点,在创建根的左子树,在创建根的右子树

要把创建的二叉树补全ABDCEF--->ABD###CE##F##

#是我们给的空的节点的标记

修改跳出条件为(*index<size&&array[*index]!='#')

`跳出条件有先后顺序,不可以写错!!!!!`

索引遇到#之后还需要往后面走

//创建根节点

//(*index++),创建根的左子树

//(*index++),创建根的右子树

递归之后其实创建的都是根节点,所有根节点创建写(*index++);

把创建的函数封装起来,方便用户调用,参数加一个无效参数,避免你设置为#,他输入$

Q:根据两个遍历的结果,要求还原出来的二叉树
A:TO DO

二叉树的销毁方式:

最后才可以销毁根节点,所以采用后序遍历规则

销毁完所有的节点之后要把Root节点置空函数体内部修改形参的值,要传形参的地址

所以销毁函数中传Root的地址!!!!!

二叉树的拷贝:

根据二叉树的概念,和创建的方法一样

查看二叉树中的叶子节点:

左右子树没有孩子的节点称为叶子节点
if(Root==NULL)
{
return 0;
}
if(Root->left==NULL&&Root->right==NULL)
{
return 1;
}
return GetLeatCount(Root->left)+GetLeatCount(Root->right);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: