zoukankan      html  css  js  c++  java
  • 数据结构与算法-二叉树

    二叉树

    树的基本概念

    向量和列表都无法兼顾静态(如寻找)和动态(如插入)操作。而树形结构可以一定程度上结合二者的优点,可以认为树是列表的列表,是一种半线性结构。

    树结构的应用:层级结构表示,表达式、文件系统、URL。

    1. 什么是树结构?
      树结构可以被看作是特殊的图结构 T = (V,E)。

    2. 有根树:
      相对于 T,Ti 称为以 ri 为根的子树,Ti = subtree(ri)。
      d = degree(r) 为 r 的(出)度数,值为顶点 r 的孩子的数量。
      一棵树中所有顶点的度数和 ∑degree(ri) 等于树的总边数,也等于总顶点数减一,即
      ∑degree(ri) = e = n-1 。任何树中边数和顶点数是同阶的。
      有序树:
      若指定 Ti 为 T 的第 i 棵子树,ri 为 r 的第 i 个孩子,这种指定了兄弟之间明显次序的树 T 则称为有序树

    3. 路径:
      对于 V 中的 k+1 个节点,通过 E 中的 k 条边依次相连,这样就构成了一条路径
      |path(v)| 。
      路径的长度被定义为 边数 = k 。
      环路:如果首节点 v0 和末节点 vk 为同一节点,则该路径被称为环路。
      在图中,如果任意两个节点之间都路径相连,则称为连通图。
      不含环路的图,称为无环图。
      树实际上是一种 无环连通图,是极小连通图 和 极大无环图(满足连通条件下边数极小,满足无环条件下边数极大)

    4. 深度与层次
      在树中,任意一个节点 v 与根之间只有唯一一条路径。
      在不致歧义的情况下,路径、节点和以此节点为根的子树可相互指代。
      节点的深度被定义为路径的长度:depth(v) = |path(v)| 。
      path(v) 上的节点,都是 v 的祖先,v 是他们的后代。除自身外,是真 祖先/后代。
      半线性:在任意深度,v 的祖先若存在则必然唯一;但 v 的后代若存在则未必唯一。
      根节点是所节点的公共祖先,深度为 0 。
      没后代的节点称为 叶节点/叶子。
      所叶节点深度中的最大值,称为树的高度。子树的高度,就是根节点的高度。height(v) = height(subtree(v))。
      任意节点 v 的深度与高度之和,不大于根节点的高度。
      空树的高度取为 -1 。

    5. 树的表示

      • 需提供的接口:

      • 如何从逻辑上表示一个树

    1) 父节点
    除根外,任一节点有且仅有一个父节点。可以将节点组织为序列,各节点分别包括其本身的信息(data)和父节点的秩或位置(parent)。这样的组织形式,向上寻找父节点和根节点效率较高,但向下寻找子节点和兄弟节点效率较低。

    性能:

    2)孩子节点
    在序列中,添加孩子(children)引用,指向以此节点为父节点的孩子节点。同时,去除其指向父节点的秩或位置(parent)。这样的组织形式,向下寻找子节点和兄弟节点效率较高,但向上寻找父节点和根节点效率较低。

    3)父节点+孩子节点
    对于一个节点,同时包括其本身的信息(data)、父节点的秩或位置(parent)和指向其孩子的引用(children)。这样解决了向上和向下的效率不均衡的问题,但是由于每个节点的孩子数量(度数不同,导致在 children 中搜索的效率较低。

    存在问题:由于父节点连着几个子节点,查询修改效率受到影响

    4)长子兄弟表示法
    上半图为父子表示法,下半图为长子兄弟表示法。
    纵向的:firstChild(),即找到以该节点为父节点的长子。
    横向的:nextSibling(),即找到以该节点为最邻近的兄节点的下一个弟节点。

    二叉树

    概念

    1. 每个节点度数不超过2的树,称为二叉树。

    2. 一般二叉树:

    3. 真二叉树:每个节点的度数都是偶数(2或0)。为原有的每个节点添加足够多的孩子节点(原度数为1则添加一个孩子,原度数为0则添加两个孩子)。

    4. 通过二叉树描述多叉树:
      对于根且序的多叉树,都可以表示为二叉树。原理可以由长子兄弟表示法解释,即将长子和兄弟两条路径看作二叉树的左右子树。

    实现

    c++实现

    BinNode类

    #pragma once
    #define BinNodePosi(T) BinNode<T>* //节点位置 
    #define stature(p) ((p) ? (p)->height: -1) //节点高度
    
    //BinNode状态与性质的判断
    #define IsRoot(x) (!((x).parent))
    #define IsLeaf(x) (!((x).lc || (x).rc))  
    #define IsLChild(x) (!((x).parent) && (&(x) == (x).parent->lc))
    #define IsRChild(x) (!((x).parent) && (&(x) == (x).parent->rc))
    #define HasParent(x) ((x).parent) 
    #define HasLChild(x) ((x).lc) 
    #define HasRChild(x) ((x).rc) 
    #define HasChild(x) (HasLChild(x) || HasRChild(x))                  //至少拥有一个孩子 
    #define HasBothChild(x) (HasLChild(x) && HasRChild(x))              //同时拥有两个孩子 
    #define sibling(p) (IsLChild(*(p)) ? (x).parent.rc: (x).parent.lc)          //兄弟 
    #define uncle(p) (sibling((p).parent))                                              //叔叔 
    #define FromParentTo(x)  ( IsRoot(x) ? _root : ( IsLChild(x) ? (x).parent->lc : (x).parent->rc ) )         //来自父亲的引用
     
    typedef enum { RB_RED, RB_BLACK } RBColor; //节点颜色
     
    template <typename T> struct BinNode{
    	BinNodePosi(T) parent;
    	BinNodePosi(T) lc;
    	BinNodePosi(T) rc; //父亲、孩子
        int npl;
        RBColor color;
    	T data; int height;  //高度、子树规模
        //构造函数
        BinNode():
            parent( nullptr ), lc( nullptr ),rc( nullptr ),height ( 0 ),npl( 1 ),color ( RB_RED ) {}
        BinNode( T e, BinNodePosi(T) p = nullptr, BinNodePosi(T) lc = nullptr, BinNodePosi(T) rc = nullptr, int h = 0, int l = 1, RBColor c = RB_RED):
            data( e ), parent( p ), lc( lc ), rc( rc ),height ( h ),npl( 1 ),color ( c ) {}
        //操作接口
        int size();
    	BinNodePosi(T) insertAsLC( T const & ); //作为左孩子插入新节点
    	BinNodePosi(T) insertAsRC( T const & ); //作为右孩子插入新节点
    	BinNodePosi(T) succ(); //(中序遍历意义下)当前节点的直接后继
    	template <typename VST> void travLevel(VST &); //子树层次遍历
    	template <typename VST> void travPre(VST &); //子树先序遍历
    	template <typename VST> void travIn(VST &); //子树中序遍历
    	template <typename VST> void travPost(VST &); //子树后序遍历
    };
    
    //作为左孩子插入
    template <typename T> BinNodePosi(T) BinNode<T>::insertAsLC(T const &e)
    	{return lc = new BinNode( e, this);}
    //作为右孩子插入
    template <typename T> BinNodePosi(T) BinNode<T>::insertAsRC(T const &e)
    	{return rc = new BinNode( e, this);}
    
    //size()
    template <typename T> int BinNode<T>::size(){//后代总数,以其为根的子树的规模
    	int s = 1; //计入本身
    	if (lc) s += lc->size(); //递归计入左子树规模
    	if (rc) s += rc->size(); //递归计入右子树规模
    	return s;
    }//O(n=|size|)
    
    

    Bintree类

    #include "binnode.h"
    #include "release.h"
    #include <iostream>
    #include <memory>
    #include "../dsa_queue_20200717/queue.h"
    
    #define max(a,b) ( a > b ? a : b)
    
    template <typename T> class BinTree{
    protected:
    	int _size;//规模
    	
    	virtual int updateHeight( BinNodePosi(T) x); //更新节点x的高度
    	void updateHeightAbove( BinNodePosi(T) x); //更新x及祖先的高度
    public:
    	BinNodePosi(T) _root; //根节点
        //构造函数
        BinTree():_size( 0 ), _root ( nullptr ) {}
        //~BinTree(){ if ( 0 < _size ) remove( _root );}
    
        //函数接口 
    	int size() const { return _size; } //规模
    	bool empty() const { return !_root;} //判空
    	BinNodePosi(T) root() const {return _root; } //树根
        
        BinNodePosi(T) insertAsRoot(T const& e); //作为根节点插入
    	BinNodePosi(T) insertAsLC(BinNodePosi(T) x, T const& e);//作为左孩子节点接入
    	BinNodePosi(T) insertAsRC(BinNodePosi(T) x, T const& e);//作为右孩子节点接入
    	BinNodePosi(T) attachAsLC(BinNodePosi(T) x, BinTree<T>* &S);//作为左子树接入
    	BinNodePosi(T) attachAsRC(BinNodePosi(T) x, BinTree<T>* &S);//作为右子树接入
    
    	int remove(BinNodePosi(T) x);//删除以节点x为根的子树
        template <typename VST> void travPre(BinNodePosi(T) x, VST& visit) { if (_root) _root->travPre(visit); }//先序遍历
        template <typename VST> void travPost(const VST& visit) { if (_root) _root->travPost(visit); }//后序遍历
    	template <typename VST> void travLevel(const VST& visit) { if (_root) _root->travLevel(visit); }//层次遍历
    	template <typename VST> void travIn( const VST& visit) { if (_root) _root->travIn(visit); }//中序遍历
    
    	void traverse (BinNodePosi(T) x, void (*)(T&) );
    };
    template <typename T> void BinTree<T>::traverse ( BinNodePosi(T) x, void (*visit )( T& ))
    {
        if( !x ) return;
    	visit( x->data );
    	traverse( x->lc, visit );
    
    	traverse( x->rc, visit );
    	
    }
    //先序遍历
    template <typename T, typename VST> void travPre(BinNodePosi(T) x, VST& visit) {
    	if( !x ) return;
    	//BinNodePosi(T) x = root();
    	visit( x->data );
    	travPre( x->lc, visit );
    	travPre( x->rc, visit );
    
    }
    //后序遍历
    template <typename T, typename VST> void travPost(BinNodePosi(T) x, VST& visit) {
    	if( !x ) return;
    	travPost( x->lc, visit );
    	travPost( x->rc, visit );
    	visit( x->data );
    
    }
    //中序遍历
    template <typename T, typename VST> void travIn(BinNodePosi(T) x, VST& visit) {
    	if( !x ) return;
    	travIn( x->lc, visit );
    	visit( x->data );
    	travIn( x->rc, visit );
    
    
    }
    //层次遍历
    template <typename T> template <typename VST> void BinNode<T>::travLevel ( VST& visit){
    	Queue<BinNodePosi(T)> Q;
    	Q.enqueue( this );
    	while( !Q.empty()){
    		BinNodePosi(T) x = Q.dequeue();visit( x->data);
    		if( HasLChild(*x )) Q.enqueue( x->lc);
    		if( HasRChild(*x )) Q.enqueue( x->rc);
    	}
    }
    //更新节点x的高度
    template <typename T>
    int BinTree<T>::updateHeight(BinNodePosi(T) x)
    {
    	return x->height = 1 + max(stature(x->lc), stature(x->rc));
    }
    
    //更新树的高度
    template <typename T>
    void BinTree<T>::updateHeightAbove(BinNodePosi(T) x) 
    {
    	while (x) { updateHeight(x); x = x->parent; }
    }
    
    //空树插入根节点
    template <typename T>
    BinNodePosi(T) BinTree<T>::insertAsRoot(T const& e)
    {
    	_size = 1; return _root = new BinNode<T> (e);
    }
    
    //作为节点x的左孩子插入
    template <typename T>
    BinNodePosi(T) BinTree<T>::insertAsLC(BinNodePosi(T) x,T const& e)
    {
    	_size++; x->insertAsLC(e); updateHeightAbove(x); return x->lc;
    }
    //作为节点x的右孩子插入
    template <typename T>
    BinNodePosi(T) BinTree<T>::insertAsRC(BinNodePosi(T) x,T const& e)
    {
    	_size++; x->insertAsRC(e); updateHeightAbove(x); return x->rc;
    }
    //S作为节点x的左子树插入
    //S本身被置空
    template <typename T>
    BinNodePosi(T) BinTree<T>::attachAsLC(BinNodePosi(T) x, BinTree<T>* &S)
    {
    	x->lc = S->_root;
    	x->lc->parent = x;
    
    	_size += S->_size;
    	updateHeightAbove(x);
    	S->_root =nullptr;
    	S->size = 0; dtl::release(S); S = nullptr; return x;
    }
    //S作为节点x的右子树插入
    //S本身被置空
    template <typename T>
    BinNodePosi(T) BinTree<T>::attachAsRC(BinNodePosi(T) x, BinTree<T>* &S)
    {
    	x->rc = S->_root;
    	x->rc->parent = x;
    
    	_size += S->_size;
    	updateHeightAbove(x);
    	S->_root = nullptr;
    	S->size = 0; dtl::release(S); S = nullptr; return x;
    }
    
    template <typename T>//二叉树删除x节点及其后代
    int BinTree<T>::remove(BinNodePosi(T) x)
    {
    	FromParentTo( *x ) = nullptr;
    	updateHeightAbove ( x->parent );
    	int n = removeAt( x ); _size -=n;
    	return n;
    }
    
    template <typename T>//删除x节点及其后代,返回删除节点数
    static int removeAt(BinNodePosi(T) x)
    {
    	if (!x)return 0;//递归基
    	int n = 1 + removeAt(x->lc) + removeAt(x->rc);
    	dtl::release(x->data); dtl::release(x); return n;
    }
    
    
    

    测试

    /*
    * The program aims to test BinTree class
    * author@Ripples
    * 20200723
    */
    #include <iostream>
    #include <stdlib.h>
    #include <stdio.h>
    #include "bintree.h"
    #include "../dsa_vector_200622/dsa_vector.h"
    
    using namespace std;
    
    template<typename T> void returnValue(T& a)
    {
        cout << "return_value: " << a << endl;
    }
    
    int main(int argc,char* argv[])
    {
    	//构造树
    	BinTree<char> bt_test;
    	bt_test.insertAsRoot('b');
    	bt_test.insertAsLC(bt_test.root(), 'a');
    	bt_test.insertAsRC(bt_test.root(), 'f');
    	bt_test.insertAsLC(bt_test.root()->rc, 'd');
    	bt_test.insertAsRC(bt_test.root()->rc, 'g');
    	bt_test.insertAsLC(bt_test.root()->rc->lc, 'c');
    	bt_test.insertAsRC(bt_test.root()->rc->lc, 'e');
    	/*
    						b
    	     	a							f
    								d				g
    							c		e
    	*/
    	//前序遍历:b,a,f,d,c,e,g
    	//后序遍历:a,c,e,d,g,f,b
    	//中序遍历:a,b,c,d,e,f,g
    	void (* visit)(char& ) = &returnValue;
    	bt_test.traverse(bt_test.root(),visit);
    
    	//删除右子树之后遍历
    	cout << "modifed:" << endl;
    	bt_test.remove(bt_test.root()->rc);
    	bt_test.traverse(bt_test.root(),visit);//b,a
    
    	return 0;
    }
    
    

    java实现

    Binnode

    package com.atguigu.Dao;
    /**
     * @anthor shkstart
     * @create 2020-08-02 20:55
     */
    public class BinNode<T> implements BinNodeImpl<T>{
    	//成员
    	public Boolean color;
    	// 颜色
    	public T data;
    	// 关键字(键值)
    	public BinNode<T> rc;
    	// 右孩子
    	public BinNode<T> lc;
    	// 左孩子
    	public BinNode<T> parent;
    	// 父亲
    	public int height;
    	public int npl;
    	//构造函数
    	public BinNode() {
    	}
    	public BinNode(T data, BinNode<T> parent) {
    		this.data = data;
    		this.parent = parent;
    	}
    	public BinNode(T data) {
    		this.data = data;
    	}
    	public BinNode(Boolean color, T data, BinNode<T> rc, BinNode<T> lc, BinNode<T> parent, int height, int npl) {
    		this.color = color;
    		this.data = data;
    		this.rc = rc;
    		this.lc = lc;
    		this.parent = parent;
    		this.height = height;
    		this.npl = npl;
    	}
    	//操作方法的实现
    	@Override
    	    public int size() {
    		int s = 1;
    		if (lc != null){
    			s += lc.size();
    		}
    		if (rc != null){
    			s += rc.size();
    		}
    		return s;
    	}
    	@Override
    	    public BinNode insertAsLC(T e) {
    		return lc = new BinNode<>(e,this);
    	}
    	@Override
    	    public BinNode insertAsRC(T e) {
    		return rc = new BinNode<>(e,this);
    	}
    	@Override
    	    public BinNode succ() {
    		BinNode<T> s = this;
    		if (rc != null){
    			s = rc;
    			while (s.lc != null){
    				s = s.parent;
    			}
    		} else {
    			while (!(s.parent != null) && (s == s.parent.rc)){
    				s = s.parent;
    			}
    		}
    		return s;
    	}
    	public int stature(){
    		if (this == null){
    			return 0;
    		} else {
    			return this.height;
    		}
    	}
    }
    

    BinTree

    package com.atguigu.Dao;
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.Stack;
    /**
     * @anthor shkstart
     * @create 2020-08-02 20:49
     */
    public class BinTree<T> implements BinTreeImpl<T>{
    	protected int _size;
    	public BinNode<T> _root;
    	// 根结点
    	//构造函数
    	public BinTree() {
    		_size = 0;
    		_root = null;
    	}
    	@Override
    	    public int size() {
    		return _size;
    	}
    	@Override
    	    public Boolean empty() {
    		return (_root != null);
    	}
    	//更新节点的高度
    	@Override
    	    public int updateHeight(BinNode<T> x) {
    		int m1 = 0;
    		int m2 = 0;
    		if (x.lc != null){
    			m1 = x.lc.height;
    		}
    		if (x.rc != null){
    			m2 = x.rc.height;
    		}
    		return x.height = 1 + Math.max(m1,m2);
    	}
    	//更新树的高度
    	@Override
    	    public void updateHeightAbove(BinNode<T> x) {
    		while (x != null){
    			updateHeight(x);
    			x = x.parent;
    		}
    	}
    	//空树插入根节点
    	@Override
    	    public BinNode<T> insertAsRoot(T e) {
    		_size = 1;
    		return _root = new BinNode<T>(e);
    	}
    	//作为节点x的左孩子插入
    	@Override
    	    public BinNode<T> insertAsLc(BinNode<T> x, T e) {
    		_size++;
    		x.insertAsLC(e);
    		updateHeightAbove(x);
    		return x.lc;
    	}
    	//作为节点x的右孩子插入
    	@Override
    	    public BinNode<T> insertAsRc(BinNode<T> x, T e) {
    		_size++;
    		x.insertAsRC(e);
    		updateHeightAbove(x);
    		return x.rc;
    	}
    	@Override
    	    public BinNode<T> attachAsLc(BinNode<T> x, BinTree<T> s) {
    		x.lc = s._root;
    		x.lc.parent = x;
    		_size += s._size;
    		updateHeightAbove(x);
    		s._root = null;
    		s._size = 0;
    		return x;
    	}
    	@Override
    	    public BinNode<T> attachAsRc(BinNode<T> x, BinTree<T> s) {
    		x.rc = s._root;
    		x.rc.parent = x;
    		_size += s._size;
    		updateHeightAbove(x);
    		s._root = null;
    		s._size = 0;
    		return x;
    	}
    	@Override
    	    public int remove(BinNode<T> x) {
    		/*IsRoot(x) ? _root : ( IsLChild(x) ? x.parent.lc : x.parent.rc )
            BinNode<T> s = FromParentTo(x);
            s = null;*/
    		if (IsRoot(x)){
    			_root = null;
    		} else {
    			if (IsLChild(x)){
    				x.parent.lc = null;
    			} else {
    				x.parent.rc = null;
    			}
    		}
    		updateHeightAbove(x.parent);
    		int n = removeAt(x);
    		_size -= n;
    		return n;
    	}
    	public int removeAt(BinNode<T> x){
    		if (x == null) return 0;
    		int n = 1 + removeAt(x.lc) + removeAt(x.rc);
    		x.lc = null;
    		x.rc = null;
    		return n;
    	}
    	//先序遍历
    	/*@Override
        public void travPre(BinNode<T> x) {
            if (x == null) return;
            visit(x);
            travPre(x.lc);
            travPre(x.rc);
        }*/
    	//改进1
    	/*@Override
        public void travPre(BinNode<T> x) {
            Stack<BinNode<T>> s = new Stack<>();
            if (x != null){
                s.push(x);
            }
            while (!s.empty()){
                x = s.pop();
                visit(x);
                if (HasRChild(x)){
                    s.push(x.rc);
                }
                if (HasLChild(x)){
                    s.push(x.lc);
                }
            }
        }*/
    	//改进2
    	@Override
    	    public void travPre(BinNode<T> x) {
    		Stack<BinNode<T>> s = new Stack<>();
    		while (true){
    			visitAlongLeftBranch(x,s);
    			if (s.empty()) break;
    			x = s.pop();
    		}
    	}
    	public void visitAlongLeftBranch(BinNode<T> x, Stack<BinNode<T>> s){
    		while (x != null){
    			visit(x);
    			s.push(x.rc);
    			x = x.lc;
    		}
    	}
    	//后序遍历
    	/*@Override
        public void travPost(BinNode<T> x) {
            if (x == null) return;
            travPost(x.lc);
            travPost(x.rc);
            visit(x);
        }*/
    	//改进
    	@Override
    	    public void travPost(BinNode<T> x) {
    		Stack<BinNode<T>> s = new Stack<>();
    		if (x != null){
    			s.push(x);
    		}
    		while (!s.empty()){
    			if (s.peek() != x.parent){
    				gotoHLVFL(s);
    			}
    			x = s.pop();
    			visit(x);
    		}
    	}
    	public void gotoHLVFL(Stack<BinNode<T>> s){
    		BinNode<T> x = new BinNode<>();
    		x = s.peek();
    		while (x != null ){
    			if (HasLChild(x)){
    				if (HasRChild(x)){
    					s.push(x.rc);
    				}
    				s.push(x.lc);
    			} else {
    				s.push(x.rc);
    			}
    			x = s.peek();
    		}
    		s.pop();
    	}
    	//中序遍历
    	/*@Override
        public void travIn(BinNode<T> x) {
            if (x == null) return;
            travIn(x.lc);
            visit(x);
            travIn(x.rc);
        }*/
    	//改进1
    	@Override
    	    public void travIn(BinNode<T> x) {
    		Stack<BinNode<T>> s = new Stack<>();
    		while (true){
    			goAlongLeftBranch(x,s);
    			if (s.empty()) break;
    			x = s.pop();
    			visit(x);
    			x = x.rc;
    		}
    	}
    	public void goAlongLeftBranch(BinNode<T> x, Stack<BinNode<T>> s){
    		while (x != null){
    			s.push(x);
    			x = x.lc;
    		}
    	}
    	//层次遍历
    	@Override
    	    public void travLevel() {
    		Queue<BinNode<T>> Q = new LinkedList<BinNode<T>>();
    		Q.add(this._root);
    		while ((Q.peek() != null)){
    			BinNode<T> x = Q.poll();
    			visit(x);
    			if (x.lc != null){
    				Q.offer(x.lc);
    			}
    			if (x.rc != null){
    				Q.offer(x.rc);
    			}
    		}
    	}
    	//感觉和先序遍历没什么区别
    	@Override
    	    public void traverse(BinNode<T> x) {
    		if (x == null) return;
    		visit(x);
    		traverse(x.lc);
    		traverse(x.rc);
    	}
    	//一个二叉树中的处理函数以及判断的函数
    	void visit(BinNode<T> x){
    		System.out.print(x.data);
    	}
    	Boolean IsRoot(BinNode<T> x) {
    		return x.parent == null;
    	}
    	Boolean IsLeaf(BinNode<T> x) {
    		return !(x.lc != null || x.rc != null);
    	}
    	Boolean IsLChild(BinNode<T> x){
    		return ((x.parent != null) && (x == x.parent.lc));
    	}
    	Boolean IsRChild(BinNode<T> x){
    		return ((x.parent != null) && (x == x.parent.rc));
    	}
    	Boolean HasParent(BinNode<T> x){
    		return (x.parent != null);
    	}
    	Boolean HasLChild(BinNode<T> x){
    		return (x.lc != null);
    	}
    	Boolean HasRChild(BinNode<T> x){
    		return (x.lc != null);
    	}
    	Boolean HasChild(BinNode<T> x) {
    		return (HasLChild(x)  || HasRChild(x) );
    	}
    	//至少拥有一个孩子
    	Boolean HasBothChild(BinNode<T> x) {
    		return (HasLChild(x)  && HasRChild(x) );
    	}
    	//同时拥有两个孩子
    	BinNode<T> FromParentTo(BinNode<T> x){
    		return ( IsRoot(x) ? _root : ( IsLChild(x) ? x.parent.lc : x.parent.rc ) );
    	}
    	//来自父亲的引用
    }
    

    测试

    package com.atguigu.Test;
    import com.atguigu.Dao.BinTree;
    /**
     * @anthor shkstart
     * @create 2020-08-04 10:56
     */
    public class bintreeTest {
    	public static void main(String[] args) {
    		BinTree<Character> bt_test = new BinTree<>();
    		bt_test.insertAsRoot('b');
    		bt_test.insertAsLc(bt_test._root,'a');
    		bt_test.insertAsRc(bt_test._root,'f');
    		bt_test.insertAsLc(bt_test._root.rc,'d');
    		bt_test.insertAsRc(bt_test._root.rc,'g');
    		bt_test.insertAsLc(bt_test._root.rc.lc,'c');
    		bt_test.insertAsRc(bt_test._root.rc.lc,'e');
    		//遍历
    		bt_test.travPre(bt_test._root);
    		System.out.println();
    		bt_test.travIn(bt_test._root);
    		System.out.println();
    		bt_test.travPost(bt_test._root);
    		System.out.println();
    		bt_test.travLevel();
    		System.out.println();
    		//删除 右子树后遍历
    		bt_test.remove(bt_test._root.rc);
    		bt_test.traverse(bt_test._root);
    	}
    }
    

    遍历

    种类

    先序遍历

    //先序遍历
    @Override
        public void travPre(BinNode<T> x) {
    	if (x == null) return;
    	visit(x);
    	travPre(x.lc);
    	travPre(x.rc);
    }
    

    //改进1
    @Override
        public void travPre(BinNode<T> x) {
    	Stack<BinNode<T>> s = new Stack<>();
    	if (x != null){
    		s.push(x);
    	}
    	while (!s.empty()){
    		x = s.pop();
    		visit(x);
    		if (HasRChild(x)){
    			s.push(x.rc);
    		}
    		if (HasLChild(x)){
    			s.push(x.lc);
    		}
    	}
    }
    

    //改进2
    @Override
        public void travPre(BinNode<T> x) {
    	Stack<BinNode<T>> s = new Stack<>();
    	while (true){
    		visitAlongLeftBranch(x,s);
    		if (s.empty()) break;
    		x = s.pop();
    	}
    }
    public void visitAlongLeftBranch(BinNode<T> x, Stack<BinNode<T>> s){
    	while (x != null){
    		visit(x);
    		s.push(x.rc);
    		x = x.lc;
    	}
    }
    

    后序遍历

    //后序遍历
    @Override
        public void travPost(BinNode<T> x) {
    	if (x == null) return;
    	travPost(x.lc);
    	travPost(x.rc);
    	visit(x);
    }
    


    //改进
    @Override
        public void travPost(BinNode<T> x) {
    	Stack<BinNode<T>> s = new Stack<>();
    	if (x != null){
    		s.push(x);
    	}
    	while (!s.empty()){
    		if (s.peek() != x.parent){
    			gotoHLVFL(s);
    		}
    		x = s.pop();
    		visit(x);
    	}
    }
    public void gotoHLVFL(Stack<BinNode<T>> s){
    	BinNode<T> x = new BinNode<>();
    	x = s.peek();
    	while (x != null ){
    		if (HasLChild(x)){
    			if (HasRChild(x)){
    				s.push(x.rc);
    			}
    			s.push(x.lc);
    		} else {
    			s.push(x.rc);
    		}
    		x = s.peek();
    	}
    	s.pop();
    }
    

    中序遍历

    //中序遍历
    @Override
        public void travIn(BinNode<T> x) {
    	if (x == null) return;
    	travIn(x.lc);
    	visit(x);
    	travIn(x.rc);
    }
    //改进1
    @Override
        public void travIn(BinNode<T> x) {
    	Stack<BinNode<T>> s = new Stack<>();
    	while (true){
    		goAlongLeftBranch(x,s);
    		if (s.empty()) break;
    		x = s.pop();
    		visit(x);
    		x = x.rc;
    	}
    }
    public void goAlongLeftBranch(BinNode<T> x, Stack<BinNode<T>> s){
    	while (x != null){
    		s.push(x);
    		x = x.lc;
    	}
    }
    

    层次遍历

    @Override
        public void travLevel() {
    	Queue<BinNode<T>> Q = new LinkedList<BinNode<T>>();
    	Q.add(this._root);
    	while ((Q.peek() != null)){
    		BinNode<T> x = Q.poll();
    		visit(x);
    		if (x.lc != null){
    			Q.offer(x.lc);
    		}
    		if (x.rc != null){
    			Q.offer(x.rc);
    		}
    	}
    }
    

    重构

    1. 对于一棵二叉树,首先要知道其中序遍历结果,然后知道其先序或后序遍历结果其中之一,即可还原二叉树。以先序遍历和中序遍历的结果为例:可以根据根节点的位置特点,确定根节点。再用根节点(r)划分左右子树的遍历序列(L和R)。

    2. 在某种情况下,先序遍历和后序遍历的结果,也可以重构二叉树。

    • 前提条件是,所要重构的二叉树是真二叉树(所有度数为偶数)。
    • 先序遍历序列中,第一个节点为根节点(v),第二个节点为左子树的根节点(l)。
    • 后序遍历序列中,最后一个节点为根节点(v),倒数第二个节点为右子树的根节点(r)。
    • 通过查找先序遍历结果中右子树的根节点(r),和后序遍历结果中左子树的根节点(l),可以确定左右子树的遍历序列。

    Huffman二叉树

    原理

    构建方式

    实例

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.Scanner;
    
    
    class Node{
        char letter;
        int power;
        Node left_son;
        Node right_son;
        public Node() { super();}
        public Node(int power) {
            this.power = power;
        }
    }
    public class CurrDesign {
    
        static Map<Character, String> map = new HashMap<Character, String>();
        public static void main(String[] args) {
            List <Node>list = codingTable();//输入
            Node tree_root = creatHFMtree(list);
            creatTable(tree_root,"");
            display();
    
            String text = inputText();
            encode(text);
    
            String code = inputCode();
            decode(code,tree_root);
        }
    
        public static String[] encode(String text) {
            String []s = new String[100];
            char []key = text.toCharArray();
            System.out.println("编码结果为:");
            for(int i=0;i<key.length;i++) {
                s[i]=map.get(key[i]);
                System.out.print(s[i]+" ");
            }
            System.out.println();
            return s;
        }
    
        public static void decode(String s,Node tree_root) {
            System.out.println("译码结果为:");
            char []num = s.toCharArray();
            Node node = tree_root;
            for(int i=0;i<num.length;i++) {
                node = check(node,num[i]);
                if(node==null) {
                    node = check(tree_root,num[i]);
                }
            }
            System.out.println(node.letter);
        }
    
        public static Node check(Node node,char c) {
            if(node.left_son!=null && c=='0')
                return node.left_son;
            else if(node.right_son!=null && c=='1'){
                return node.right_son;
            }
            System.out.print(node.letter);
            return null;
        }
    
        public static Object getKey(Object value){
            for(Object key: map.keySet()){
                if(map.get(key).equals(value)){
                    return key;
                }
            }
            return null;
        }
    
        public static String inputText() {
            Scanner in = new Scanner(System.in);
            System.out.println("请输入要编码的文本,只含大写字母:");
            String text = in.next();
            return text;
        }
    
        public static String inputCode() {
            Scanner in = new Scanner(System.in);
            System.out.println("请输入编码:");
            String code = in.next();
            in.close();
            return code;
        }
    
        public static  List<Node> codingTable(){
            List <Node>list = new ArrayList<Node>();
            int []num = {186,64,13,22,32,103,21,15,47,57,1,2,32,20,57,63,15,1,48,51,80,23,8,18,1,16};
            Node node = null;
            for(int n=0;n<26;n++) {
                node = new Node();
                node.letter = (char)('A'+n);
                node.power = num[n];
                list.add(node);
            }
            return list;
        }
    
        public static void display() {
            System.out.println("The huffman coding table are:");
            System.out.println(map.toString());
        }
    
        public static Node creatHFMtree(List<Node> list){
            Node p = null;
            int n = 0;
            while(!list.isEmpty()) {
                if(n!=0) {
                    list.add(p);
                }
                Node min1 = new Node(1000);
                Node min2 = new Node(999);
                for(Node node:list) {
                    if(node.power < min1.power) {
                        if(node.power < min2.power) {
                            min1 = min2;
                            min2 = node;
                        }else {
                            min1 = node;
                        }
                    }
                }
                p = new Node(min1.power+min2.power);
                p.left_son  = min2;
                p.right_son = min1;
                list.remove(min1);
                list.remove(min2);
                n++;
            }
            return p;
        }
    
        public static void creatTable(Node node,String coding){
            if(node.left_son!=null) {
                creatTable(node.left_son,coding+"0");
            }
            if(node.right_son!=null) {
                creatTable(node.right_son,coding+"1");
            }
            if(node.left_son==null && node.right_son==null) {
                map.put(node.letter, coding);
            }
        }
    }
    
  • 相关阅读:
    hdu5056(找相同字母不出现k次的子串个数)
    POJ 3613 快速幂+Floyd变形(求限制k条路径的最短路)
    POJ 3613 快速幂+Floyd变形(求限制k条路径的最短路)
    Poj 3522 最长边与最短边差值最小的生成树
    Poj 3522 最长边与最短边差值最小的生成树
    POJ 1716 区间最小点个数
    POJ 1716 区间最小点个数
    POJ 1679 判断最小树是否唯一
    POJ 1679 判断最小树是否唯一
    hdu 5020 求三点共线的组合数(容器记录斜率出现次数)
  • 原文地址:https://www.cnblogs.com/suit000001/p/13436362.html
Copyright © 2011-2022 走看看