1.树在本质上其实就是不包含回路的连通无向图;
java
2.关于树的一些特色:
(1).任意两个结点有且只有惟一的一条路径链接;
(2).n个结点,那么恰好n-1条边;
(3).在一棵树中加一条边将会构成一个回路;
3.根:一棵树有且只有一个根结点,好比上图中的数值为1的点就是根结点;
子结点:上图中除了1其他都是子结点,没有父结点的结点是根结点(祖先);
叶结点:没有子结点的结点就是叶结点,如上图的3.4.5
其他既不是根结点又不是叶结点的叫作内部结点,如上图的2;
最后每一个结点是有深度的,好比3号节点的深度(从根结点到这一层的层数)是2;数组
1.定义:每一个结点最多有两个儿子,分别是左儿子、右儿子;递归定义:二叉树要么为空,要么由根结点、左子树、右子树组成;二叉树又分为满二叉树和彻底二叉树;
2.满二叉树:每一个内部结点都有两个儿子,也就是全部的叶结点都有相同的深度;
3d
3.满二叉树深度与结点的关系:假如深度为n,那么结点2n-1;第n层上,结点为2(n-1);
4.彻底二叉树:除了最右边位置上有一个或者几个叶结点缺乏外,其他都是丰满的
code
(1).对于彻底二叉树:咱们能够用一个一维数组来存储它,从根结点开始
blog
(2).若是给父结点编号为k,那么他的左儿子就是2k,右儿子2k+1;
(3).若是一棵二叉树有N个结点,那么这个彻底二叉树的高度为log2N(2)为底;
彻底二叉树的最典型应用就是——堆;排序
import java.util.Scanner; public class D堆排序 { static Scanner in=new Scanner(System.in); static int n;static int num=in.nextInt(); static int []h=new int [num+1]; public static void swap(int x,int y) { int t; t=h[x]; h[x]=h[y]; h[y]=t; return; } public static void siftdown(int i) { int t,flag=0; while(i*2<=n&&flag==0) { if(h[i]>h[i*2]) { t=i*2; } else t=i; if(i*2+1<=n) { if(h[t]>h[i*2+1]) t=i*2+1; } if(t!=i) { swap(t,i); //i=t; } else flag=1; } return; } public static void creat() { int i; for(i=n/2;i>=1;i--) { //从最后一个非叶结点到第一个结点依次进行向下调整 siftdown(i); } return; } public static int deletemax() { int t; t=h[1]; h[1]=h[n]; n--; siftdown(1); return t; } public static void main(String[] args) { // TODO Auto-generated method stub int i=0; for(i=1;i<=num;i++) { h[i]=in.nextInt(); } n=num; creat();//建堆 for(i=1;i<=num;i++) { System.out.print(deletemax()+" "); } } }
1.建立堆(最小堆)递归
public static void creat() { int i; for(i=n/2;i>=1;i--) { //从最后一个非叶结点到第一个结点依次进行向下调整 siftdown(i); } return; }
为何是从n/2开始呢?由于全部的叶结点都没有儿子,天然而然叶结点都符合最小堆的特色,因此这里就再也不须要考虑叶结点,直接从最后一个非叶结点开始起进行调整,一直到第一个结点。class
2.在建立堆的过程当中,对全部的子树进行调整,当全部的子树知足条件时,整棵树就必定知足了条件。import
3.采用删除最大元素的方式来输出二叉树
public static int deletemax() { int t; t=h[1]; h[1]=h[n]; n--; siftdown(1); return t; }
将堆顶的元素返回输出,而后将最大的元素放到堆顶再进行调整,n--,直到为空。