zoukankan      html  css  js  c++  java
  • 学习记录:二叉树

    二叉树

    二叉树的性质

    每个节点最多都有两个子节点的树称为二叉树。其性质与定义有:

    • (i)层最多有(2^{i-1})个节点
    • 满二叉树:若每一层的节点数都是满的(都为(2^{i-1})),则为满二叉树
    • 完全二叉树:一棵满二叉树只在最后一层有缺失,则称为完全二叉树

    而对于完全二叉树,它的子节点与父结点还有一种性质

    • 对于编号为(i)的节点,其父节点为(i/2)

    • 如果编号为(i)的节点有子节点,则其左节点编号为(2i)(2i+1)

      PS:编号从1开始

    JaIe6x.jpg

    二叉树的储存

    一般用指针,和链表同理

    struct node{
    	int value;
    	node *l,*r;
    };
    

    用数组也可以,而且能更为直观的表现完全二叉树中子节点与父节点的关系,但是要注意编号从1开始

    二叉树的遍历

    先用数组模拟来实现遍历,这里设二叉树为 int num[]={-1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

    广度优先遍历

    void BFS(int start)
    {
    	queue<int> q;
    	q.push(start);
    	cout<<num[start]<<" ";
    	while (!q.empty()){
    		int t1=q.front()*2,t2=q.front()*2+1;
    		if (t1<16){
    			q.push(t1);
    			cout<<num[t1]<<" ";
    		}
    		if (t2<16){
    			q.push(t2);
    			cout<<num[t2]<<" ";
    		}
    		q.pop();
    	}
    }
    

    深度优先遍历

    深度遍历一颗二叉树共有三种方式

    • 先序遍历:按父节点->左儿子->右儿子的顺序遍历
    • 中序遍历:按左儿子->父节点->右儿子的顺序遍历
    • 后序遍历:按左儿子->右儿子->父节点的顺序遍历

    【数据结构】理解二叉树的三种遍历--前序、中序、后序 +层序(简明易懂)强烈推荐这一篇,这一篇博客写的非易懂

    不难发现三种遍历其实就互相调整了一下顺序,用递归可以很简单的实现

    void preorder(int root)
    {
    	if (root>16)
    		return ;
    	cout<<num[root]<<' ';
    	preorder(root*2);
    	preorder(root*2+1);
    }
    void inorder(int root)
    {
    	if (root>16)
    		return ;
    	inorder(root*2);
    	cout<<num[root]<<' ';
    	inorder(root*2+1);
    }
    void postorder(int root)
    {
    	if (root>16)
    		return ;
    	postorder(root*2);
    	postorder(root*2+1);
    	cout<<num[root]<<' ';
    }
    

    如果是用指针实现的,那么把退出条件改一下,root*2替换为左指针,root*2+1替换为右指针即可

    根据遍历结果确定二叉树

    确定二叉树的结构,需要至少两种遍历结果

    • 先序遍历+中序遍历
    • 中序遍历+后序遍历

    如果是先序遍历+后序遍历则无法确定一棵二叉树,如图。这时先序遍历+后序遍历的结果相同

    JdmkUf.jpg

    先序遍历+中序遍历

    从推荐的那篇博客,不难发现中序遍历有一个特点:对于一个节点,在中序遍历的结果中,这个节点的左边的节点在二叉树中都在原节点的左边,右边同理。(因为中序遍历可以看作二叉树的投影)

    这里以hdu 1710为例,这道题就是已知先序遍历+中序遍历,求后序遍历

    先序遍历:1 2 4 7 3 5 8 9 6

    中序遍历:4 7 2 1 8 5 9 3 6

    1. 先序的第一个数是整个二叉树的根,再看中序,根据上面说的中序遍历特点可以把所有数字分成两块,472和85936,前者在1的右边,后者在1的左边
    2. 先序的第二个数是前一子树的根,以此类推,4 7又可以放在2的右边
    3. 递归求解,获得一棵二叉树~

    JdQdNq.jpg

    图示过程如上

    hdu 1710代码如下

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e3+10;
    int pre[maxn],in[maxn],pos[maxn],n,pla;
    void solve(int l,int r)
    {
    	if (l>r) return ;
    	pla++;
    	if (l==r){
    		printf("%d ",in[l]);
    		return ;
    	}
    	int temp=pla;
    	for (int i=l;i<=r;i++){
    		if (pre[temp]==in[i]){
    			solve(l,i-1);
    			solve(i+1,r);
    			break;
    		}
    	}
    	printf("%d",pre[temp]);
    	if (temp>1)
    		printf(" ");
    
    }
    int main ()
    {
    	while (~scanf("%d",&n)){
    		for (int i=1;i<=n;i++)
    			scanf("%d",&pre[i]);
    		for (int i=1;i<=n;i++)
    			scanf("%d",&in[i]);
    		pla=0;
    		solve(1,n);
    		cout<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    全站仪定向距离差 方向不差 这样敢放线吗
    关于老王
    cad巧用插件自定义填充图形
    老王教你永不会错的测量坐标方位角计算方法
    jqgrid 点击列头的超链接或按钮时,不触发列排序事件
    jqgrid 将列头设置为超链接或按钮
    jqgrid 设置隔行换色
    jqgrid 设置行编辑为本地端编辑状态
    jqgrid 让隐藏的列在编辑状态时出现且可编辑
    jqgrid 设置编辑行中的某列为下拉选择项
  • 原文地址:https://www.cnblogs.com/Salty-Fish/p/12760772.html
Copyright © 2011-2022 走看看