数据结构与算法实践系列文章(七)树

树(Tree)是n(n≥0)个结点的有限集,它或为空树(n= 0);或为非空树,对于非空树T:

(1)有且仅有一个称之为根的结点;

(2)除根结点以外的其余结点可分为不同的子树。

  • 结点:树的数据元素

  • 结点的度:结点挂接的子树数

  • 结点的层次:从根节点到该结点的层数

  • 路径:顺着连接节点的边从一个节点到另一个节点,所经历的节点顺序

  • 根节点:树最上面的节点称为根节点,一棵树只有一个根,而且根到任何一个节点有且只有一条路径

  • 父节点:每个节点都有一条边向上连接到另一个节点,这个节点就称是下面的节点的父节点

  • 子节点:每个节点都有一条边向下连接到另一个节点,下面的节点称为该节点的子节点

  • 叶子节点:没有子节点的节点称为叶子节点

    扫描二维码关注公众号,回复: 14705538 查看本文章
  • 子树:每个节点都可以作为一个子树的根,它和它所有的子节点,子节点的节点组合起来就是一个子树

  • 遍历:先序,中序,后序

  • 前序:1.访问根节点,2,左子树,3.右子树

  • 中序:左 ,根, 右

  • 后序 左,右,根

  • 访问:访问一个节点是为了在这个节点上执行一些操作,如查看节点的数据项,但是如果仅仅是经过一个节点,不认为是访问了这个节点

  • 层:一个节点的层数是指从根节点开始到这个节点有多少代

  • 树的度:所有结点度中的最大值

  • 树的深度:值所有结点中最大的层数

二叉树

定义:

是n个结点所构成的集合。

树的节点最多有两个子节点,称为二叉树

特点

结点的度小于等于2

有序树 查找效率O(n)

性质

在二叉树的第i层上至多有2^i-1个结点。第i层上至少有1个结点

深度为k的二叉树至多有2^k -1个结点,深度为k时至少有k个结点

对于任何一颗二叉树,若度为2的结点树有n2个则叶子树n0必定为n2+1(即 n0=n2+1)

具有n个结点的完全二叉树的深度必为log2n+1 以2为底的n次方的对数+1

对于完全二叉树,若从上至下,从左至右编号,则编号为i的结点,其左孩子编号必为2i,其右孩子的编号必为2i+1,其双亲的编号必为i/2

满二叉树

一棵深度为k且有2^k -1个结点的二叉树(特点:每层都充满了结点)满二叉树是完全二叉树的一个特例

完全二叉树

深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中的编号从1到n的结点一一对应。

二叉树的遍历

sDJ30f.png

DLR - 先序遍历, 即先根在左再右。 A B D E C

LDR - 中序遍历,即先左再根再右。 D B E A C

LRD - 后序遍历,即先左再右再根。 D E B C A

二叉树的实现(递归实现)

c语言
#include <stdio.h>
#include <stdlib.h>
typedef int Elem;
struct BinNode{
    
    
    Elem data;
    struct BinNode *left;
    struct BinNode *right;
}
typedef struct BinNode* BinTree;
// 初始化
BinTree initBinTree(Elem x){
    
    
    BinTree r;
    r = (BinTree) malloc(sizeof(struct BinNode));
    r->data = x;
    r->left = r->right=NULL;
    return r;
}
// 先序遍历(递归)
void preprint(BinTree r){
    
    
    if(r==NULL) return;
    printf("%d ",r->data);
    preprint(r->left);
    preprint(r->right);
}
//中序遍历(递归)
void inreprint(BinTree r){
    
    
    if(r==NULL) return;
    inreprint(r->left);
    printf("%d ",r->data);
    inreprint(r->right);
}
//后续遍历(递归)
void afterreprint(BinTree r){
    
    
    if(r==NULL) return;
    afterreprint(r->left);
    afterreprint(r->right);
    printf("%d ",r->data);
}
// 根结点,左子树 右子树 (先序遍历)
BinTree findX(BinTree r, Elem x){
    
    
    if(!r) return NULL;
    if(r->data == x) return r;
    BinTree found;
    found = findX(r->left,x);
    return found ? found : findX(r->right,x);
}
//打印树和其深度
void printTree(BinTree r, int depth){
    
    
    for(int i=0;i<depth;i++) printf(" ");
    if(!r){
    
    
        printf("[/]\n");
    }else{
    
    
        printf("%d\n",r->data);
        printTree(r->left,depth+1);
        printTree(r->right,depth+1);
    }
}
// 插入
int insert(BinTree bt,Elem p, int LorR,Elem x){
    
    
    BinTree found;
    found = findX(bt,p);
    if(LorR == 0){
    
    
        if(found->left) return 0;
        found->left = initBinTree(x);
    }else{
    
    
        if(found->right) return 0;
        found->right = initBinTree(x);
    }
    return 1;
}
int main(){
    
    
    BinTree bt = initBinTree(11);
    insert(bt,11,0,22);
    insert(bt,11,1,33);
    insert(bt,22,0,44);
    insert(bt,33,0,55);
    printTree(bt,0);
    preprint(bt);
    return 0;
}
c++
#include <iostream>
using namespace std;
//使用模板
template<class Elem>
struct BinNode{
    Elem data;
    BinNode<Elem> *left;
    BinNode<Elem> *right;
    BinNode(Elem x){
    	data = x;
    	left=right=NULL;
    }
};
template<class Elem>
class BinTree{
protected:
    BinNode<Elem> *root;
    // 先序遍历(递归)
    void rereprint(BinNode<Elem> *r){
    	if(r==NULL) return;
    	//先访问根。递归访问左子树,递归访问右子树
    	cout << r->data << ' ';
    	rereprint(r->left);
    	rereprint(r->right);
    }
    // 中序遍历(递归)
    void reinprint(BinNode<Elem> *r){
    	if(r==NULL) return;
    	// 递归访问左树,访问根结点,遍历右子树
    	reinprint(r->left);
    	cout << r->data << ' ';
    	rereprint(r->right);
    }
    // 后续遍历(递归)
    void reafterprint(BinNode<Elem> *r){
    	if(r==NULL) return;
    	// 递归访问左树,遍历右子树,访问根结点,
    	reafterprint(r->left);
    	reafterprint(r->right);
    	cout << r->data << ' ';
    }
    //递归查找
    BinNode<Elem>* rfindX(Elem x ,BinNode<Elem> *root){
    	if(!root) return NULL;
		if(root->data == x) return root;
		BinNode<Elem> *found;
		found = rfindX(x,r->left);
		return found ? found : rfindx(x,x->right);
    }
    // 打印 以规定的形势
    void rprint(BinNode<Elem> *root,int depth){
    	
    	for(int i=0;i<depth;i++) cout << " ";
    	if(!root) {
    		cout<< "[/]" << endl;
    	}else{
    		cout << r->data<<endl;
    		rprint(r->left,depth+1);
    		rprint(r->right,depth+1);
    	}
    	
    }
public:
	BinNode(){ root = NULL;}
	// 构造函数
	BinTree(Elem r){
		root = new BinNode<Elem>(r);
	}
	// 析构函数
	~BinTree(){}
	// 先序遍历
	void preprint(){
		rereprint(root);
		cout << endl;	
	}
	// 中序遍历
	void inprint(){
		reinprint(root);
	}
	// 后续遍历
	void reafterprint(){
		reafterprint(root);
	}
	// 查找元素返回结点的地址
	BinNode<Elem>* findX(Elem x){
		return rfindX(x,root)
	}
	// 插入
	bool insert(Elem parent,int leftOrRight,Elem x){
		BinNode<Elem> *found;
		found = findX(parent);
		// 如果found不为null
		if(!found) return false;
		if(leftOrRight == 0){
			if(found->left) return false;
			found->left = new BinNode<Elem>(x);
		}else{
			if(found->right) return false;
			found->right = new BinNode<Elem>(x);
		}
		return true;
	}
	// 打印
	void print(){
		rprint(root,0)
	}
};
int main(){
    BinTree<int> bt(11);
    // 插入结点 在结点为11的,0是左子树,插入元素22
    bt.insert(11,0,22);
    bt.insert(11,0,33);
    bt.insert(33,0,44);
     // 打印树先序
    bt.preprint();
    // 中序
    bt.inprint();
    // 后续
    bt.reafterprint();
    return 0;
}
python
class BinNode:
    def _init_(self,data):
        self.data=data;
        self.left = None;
        self.right = None;
class BinTree:
    def _init_(self,data):
		self.root = BinNode(data);
    def preprint(self,r):
        if r is None:
            return
        print(r.data,end=' ');
        self.preprint(r.left)
        self.preprint(r.right)
    def findX(self, r, x):
        if r is None:
			return
        if r.data == x:
           return r
        found = self.findX(r.left,x)
        if found is not None :
           return found
        return self.findX(r.right,x)
    # 插入 root ,parent ,是否是左子树,元素
    def insert(self,r,p,lorr,x):
        found = self.findX(r,p)
        if found is None:
            return
        if lorr == 0:
            if found.left is not None:
                return
            found.left =BinNode(x)
         else:
            if found.right is not none:
                return
            found.right =BinNode(x)
bt=BinTree(11)
bt.insert(bt,root,11,0,22)
bt.insert(bt,root,11,1,33)
bt.insert(bt,root,22,1,44)
bt.insert(bt,root,22,0,55)
bt.preprint(bt.root)
java
package com.kaysanshi.testArray;

import org.omg.CosNaming.NamingContextExtPackage.StringNameHelper;

/**
 * 树中能够快速的查找数据项,和插入数据项,删除数据项
 * 树的概念:
 * 路径:顺着连接节点的边从一个节点到另一个节点,所经历的节点顺序
 * 根节点:树最上面的节点称为根节点,一棵树只有一个根,而且根到任何一个节点有且只有一条路径
 * 父节点:每个节点都有一条边向上连接到另一个节点,这个节点就称是下面的节点的父节点
 * 子节点:每个节点都有一条边向下连接到另一个节点,下面的节点称为该节点的子节点
 * 叶子节点:没有子节点的节点称为叶子节点
 * 子树:每个节点都可以作为一个子树的根,它和它所有的子节点,子节点的节点组合起来就是一个子树
 * 遍历:先序,中序,后序
 * 前序:1.访问根节点,2,左子树,3.右子树
 * 中序:左 ,根, 右
 * 后序 左,右,根
 * 访问:访问一个节点是为了在这个节点上执行一些操作,如查看节点的数据项,但是如果仅仅是经过一个节点,不认为是访问了这个节点
 * 层:一个节点的层数是指从根节点开始到这个节点有多少代
 * 二叉树:
 * 树的节点最多有两个子节点,称为二叉树
 *
 * @author leoill
 * @date 2019年4月28日
 */
public class Tree {
    
    
    //根
    private TreeNode root;

    /**
     * 插入节点:
     * 从根节点开始查找一个相应的节点,这个节点将称为新插入的节点的父节点。
     * 当父节点找到后通过判断新节点值的大小决定连接在左节点还是右节点
     *
     * @param value
     */
    public void insert(long value) {
    
    
        //封装节点
        TreeNode node = new TreeNode(value);
        //引用当前节点
        TreeNode current = root;
        //引用父节点

        TreeNode parent;
        //如果root为null,也就是第一个插入的时候
        if (root == null) {
    
    
            root = node;
            return;
        } else {
    
    
            while (true) {
    
    
                //父节点指向当前的节点
                parent = current;
                //如果当前的指向的节点的数据比插入的大,则向左走
                if (current.data > value) {
    
    
                    current = current.leftChild;
                    if (current == null) {
    
    
                        parent.leftChild = node;
                        return;
                    }
                } else {
    
    
                    current = current.rightChild;
                    if (current == null) {
    
    
                        parent.rightChild = node;
                        return;
                    }
                }

            }
        }
    }

    /**
     * 两个参数的
     *
     * @param value
     */
    public void insert(long value, String string) {
    
    
        //封装节点
        TreeNode node = new TreeNode(value, string);
        //引用当前节点
        TreeNode current = root;
        //引用父节点

        TreeNode parent;
        //如果root为null,也就是第一个插入的时候
        if (root == null) {
    
    
            root = node;
            return;
        } else {
    
    
            while (true) {
    
    
                //父节点指向当前的节点
                parent = current;
                //如果当前的指向的节点的数据比插入的大,则向左走
                if (current.data > value) {
    
    
                    current = current.leftChild;
                    if (current == null) {
    
    
                        parent.leftChild = node;
                        return;
                    }
                } else {
    
    
                    current = current.rightChild;
                    if (current == null) {
    
    
                        parent.rightChild = node;
                        return;
                    }
                }

            }
        }
    }

    /**
     * 查找节点
     *
     * @param value
     */
    public TreeNode find(long value) {
    
    
        //引用一个当前节点,从根节点开始
        TreeNode current = root;
        //循环:只要查找的节点不等于当前节点的数据项
        while (current.data != value) {
    
    
            //进行比较,小于value则在右子树查找,否则在左边查找
            if (current.data > value) {
    
    
                current = current.leftChild;
            } else {
    
    
                current = current.rightChild;
            }
            if (current == null) {
    
    
                return null;
            }
        }
        return current;
    }

    /**
     * 删除二叉树节点
     * 删除之前首先要查找要删的节点,找到节点后,这个删除的节点可能有以下情况
     * 1.该节点是叶子节点,没有子节点:要删除叶节点,只需改变该节点的父节点的引用,将指向该节点的引用设置为null就可以了
     * 2.该节点有一个子节点:改变父节点的引用,将其指向要删除的节点的子节点、
     * 3.该节点有两个子节点,要删除有两个子节点的节点,就需要使用它的中序后继来替代该节点
     *
     * @param value
     * @return
     */
    public boolean delete(long value) {
    
    
        //引用当前节点,从根节点开始
        TreeNode current = root;
        //应用当前节点的父节点
        TreeNode parent = root;
        //是否为左节点
        boolean isLeftNode = true;
        while (current.data != value) {
    
    
            parent = current;
            //这里是比较当前的值和当前节点的大小
            if (current.data > value) {
    
    
                //如果当前值大于删除的值,则则向左面查找
                current = current.leftChild;
                isLeftNode = true;
            } else {
    
    
                //如果当前值小于删除的值则向右面查找,直到找到
                current = current.rightChild;
                isLeftNode = false;
            }
            //如果找不到
            if (current == null) {
    
    
                return false;
            }
        }
        //删除叶子节点,也就是该节点没有子节点
        if (current.leftChild == null && current.rightChild == null) {
    
    
            //如果是根
            if (current == root) {
    
    
                root = null;
                //如果 它是父节点的左子节点
            } else if (isLeftNode) {
    
    
                parent.leftChild = null;
            } else {
    
    
                parent.rightChild = null;
            }

            //删除的节点只有左子节点
        } else if (current.rightChild == null) {
    
    
            if (current == root) {
    
    
                root = current.leftChild;
            } else if (isLeftNode) {
    
    
                parent.leftChild = current.leftChild;
            } else {
    
    
                parent.rightChild = current.leftChild;
            }
            //删除的节点只有右子节点
        } else if (current.leftChild == null) {
    
    
            if (current == root) {
    
    
                root = current.rightChild;
            } else if (isLeftNode) {
    
    
                parent.leftChild = current.rightChild;
            } else {
    
    
                parent.rightChild = current.rightChild;
            }
            //删除的节点
        } else {
    
    
            TreeNode successor = getSuccessor(current);
            if (current == root) {
    
    
                root = successor;
            } else if (isLeftNode) {
    
    
                parent.leftChild = successor;
            } else {
    
    
                parent.rightChild = successor;
            }
            successor.leftChild = current.leftChild;
        }

        //表示删除成功
        return true;

    }

    /**
     * 中序后继节点,
     *
     * @param delNode
     * @return
     */
    public TreeNode getSuccessor(TreeNode delNode) {
    
    
        TreeNode successor = delNode;
        TreeNode successorParent = delNode;
        TreeNode current = delNode.rightChild;
        while (current != null) {
    
    
            successorParent = successor;
            successor = current;
            current = current.leftChild;

        }
        if (successor != delNode.rightChild) {
    
    
            successorParent.leftChild = successor.rightChild;
            successor.rightChild = delNode.rightChild;
        }

        return successor;
    }

    /**
     * 前序遍历:前序:1.访问根节点,2,左子树,3.右子树
     * 使用递归遍历
     *
     * @param localNode
     */
    public void frontTraversal(TreeNode localNode) {
    
    
        if (localNode != null) {
    
    
            //访问根节点
            System.out.println(localNode.data + "," + localNode.sdata);
            //前序遍历左子树
            frontTraversal(localNode.leftChild);
            //前序遍历右子树
            frontTraversal(localNode.rightChild);
        }
    }

    /**
     * 中序遍历
     * 递归遍历
     * 中序:左 ,根, 右
     * 就是会从小到大一次排列
     *
     * @param localNode
     */
    public void centerTraversal(TreeNode localNode) {
    
    
        //先中序遍历左子树
        if (localNode != null) {
    
    
            //中序遍历左子树
            centerTraversal(localNode.leftChild);
            //访问根节点
            System.out.println(localNode.data + "," + localNode.sdata);
            //中序遍历右子树
            centerTraversal(localNode.rightChild);
        }
    }

    /**
     * 后序遍历:
     * 左 ,右,根
     *
     * @param localNode
     */
    public void lastTraversal(TreeNode localNode) {
    
    
        if (localNode != null) {
    
    
            //后序遍历左子树
            lastTraversal(localNode.leftChild);
            //后序遍历右子树
            lastTraversal(localNode.rightChild);
            //访问根节点
            System.out.println(localNode.data + "," + localNode.sdata);
        }
    }


    /**
     * 测试
     *
     * @param args
     */
    public static void main(String[] args) {
    
    
        Tree tree = new Tree();
        tree.insert(1, "zhang");
        tree.insert(12, "ASD");
        tree.insert(13, "BHD");
        tree.insert(14, "HUA");
        tree.insert(10, "DOS");
        tree.insert(11, "NOD");
        tree.centerTraversal(tree.root);
        //删除子节点没有
        tree.delete(1);
        System.out.println();
        tree.centerTraversal(tree.root);
        System.out.println();
        //删除删除该节点有一个子节点
        tree.delete(11);
        tree.centerTraversal(tree.root);
        System.out.println();
        //删除
        tree.delete(14);
        tree.centerTraversal(tree.root);
    }

}

/**
 * 二叉树节点
 *
 * @author leoill
 * @date 2019年4月28日
 */
class TreeNode {
    
    
    //数据项
    public long data;
    //数据项
    public String sdata;
    //左子节点
    public TreeNode leftChild;
    //右子节点

    public TreeNode rightChild;

    public TreeNode(long data, String sdata) {
    
    
        this.data = data;
        this.sdata = sdata;
    }

    public TreeNode(long data) {
    
    

        this.data = data;
    }

}

二叉树的实现(迭代方式,使用栈)

C++
#include <iostream>
#include <stack>
using namespace std;
//使用模板
template<class Elem>
struct BinNode{
    Elem data;
    BinNode<Elem> *left;
    BinNode<Elem> *right;
    BinNode(Elem x){
    	data = x;
    	left=right=NULL;
    }
};
template<class Elem>
class BinTree{
protected:
    BinNode<Elem> *root;
    // 先序遍历(迭代)
    void ipreprint(BinNode<Elem> *r){
    	//需要使用栈来进行,目的记录是如何走的。把结点的指针压入栈
    	stack<BinNode<Elem>*> st;
    	if(r==NULL) return;
    	// 一直向左子树(访问压榨,向左,左为空弹栈,向右,回到根打印)
    	while(r){
    		cout << r->data << ' ';
    		st.push(r); // 压栈
    		r=r->left;
    		while(r== NULL && !st.empty() ){
    			// 左边空时
    			r=st.top(); // 记录栈顶元素
    			st.pop(); // 弹出栈
    			r=r->right;// 向右走一步
    		}
    	}
    }
    // 中序遍历(迭代)
    void iinprint(BinNode<Elem> *r){
    	//需要使用栈来进行,目的记录是如何走的。把结点的指针压入栈
    	stack<BinNode<Elem>*> st;
    	if(r==NULL) return;
    	while(r){
    		st.push(r); // 压栈
    		r=r->left;
    		while(r== NULL && !st.empty() ){
    			// 左边空时
    			r=st.top(); // 记录栈顶元素
    			st.pop(); // 弹出栈
    			cout << r->data << ' ';
    			r=r->right;// 向右走一步
    		}
    	}
    }
    // 后续遍历(迭代)
    void reafterprint(BinNode<Elem> *r){
    	//需要使用栈来进行,目的记录是如何走的。把结点的指针压入栈
    	stack<BinNode<Elem>*> st;
    	
    }
    //递归查找
    BinNode<Elem>* rfindX(Elem x ,BinNode<Elem> *root){
    	if(!root) return NULL;
		if(root->data == x) return root;
		BinNode<Elem> *found;
		found = rfindX(x,r->left);
		return found ? found : rfindx(x,x->right);
    }
    // 打印 以规定的形势
    void rprint(BinNode<Elem> *root,int depth){
    	
    	for(int i=0;i<depth;i++) cout << " ";
    	if(!root) {
    		cout<< "[/]" << endl;
    	}else{
    		cout << r->data<<endl;
    		rprint(r->left,depth+1);
    		rprint(r->right,depth+1);
    	}
    	
    }
public:
	BinNode(){ root = NULL;}
	// 构造函数
	BinTree(Elem r){
		root = new BinNode<Elem>(r);
	}
	// 析构函数
	~BinTree(){}
	// 先序遍历
	void ipreprint(){
		ipreprint(root);
		cout << endl;	
	}
	// 中序遍历
	void inprint(){
		reinprint(root);
	}
	// 后续遍历
	void reafterprint(){
		reafterprint(root);
	}
	// 查找元素返回结点的地址
	BinNode<Elem>* findX(Elem x){
		return rfindX(x,root)
	}
	// 插入
	bool insert(Elem parent,int leftOrRight,Elem x){
		BinNode<Elem> *found;
		found = findX(parent);
		// 如果found不为null
		if(!found) return false;
		if(leftOrRight == 0){
			if(found->left) return false;
			found->left = new BinNode<Elem>(x);
		}else{
			if(found->right) return false;
			found->right = new BinNode<Elem>(x);
		}
		return true;
	}
	// 打印
	void print(){
		rprint(root,0)
	}
};
int main(){
    BinTree<int> bt(11);
    // 插入结点 在结点为11的,0是左子树,插入元素22
    bt.insert(11,0,22);
    bt.insert(11,0,33);
    bt.insert(33,0,44);
     // 打印树先序
    bt.preprint();
    // 中序
    bt.inprint();
    // 后续
    bt.reafterprint();
    return 0;
}

统计有无后代人的数量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6FkR6xyu-1621490188536)(https://s3.ax1x.com/2021/01/17/srHM40.png)]

// 二叉树的先序中序后序实现

#include <iostream>
using namespace std;

template<class Elem>
struct BinNode{
    Elem data;
    BinNode<Elem>* left;
    BinNode<Elem>* right;
    BinNode(Elem x){
        data=x;
        left=right=NULL;
    }
};

template<class Elem>
class BinTree{
protected:
    BinNode<Elem>* root;
    // 先序遍历
    void rpreprint(BinNode<Elem>* r){   // 对于传指针,一定不要掉以轻心,要首先看一下指针是不是空指针
        if(r==NULL) return;
        cout<<r->data<<" ";
        rpreprint(r->left);
        rpreprint(r->right);
    }
    // 中序遍历
    void rinprint(BinNode<Elem>* r){
        if(r==NULL) return;
        rinprint(r->left);
        cout<<r->data<<" ";
        rinprint(r->right);
    }
    // 后续遍历
    void rpostprint(BinNode<Elem>* r){
        if(r==NULL) return;
        rinprint(r->left);
        rinprint(r->right);
        cout<<r->data<<" ";
    }
    // 数叶子结点
    int countLeaves(BinNode<Elem>* r){
        if(r==NULL) return 0;
        // 判断是不是只有一个根结点
        if(r->left==NULL && r->right==NULL) return 1;
        return countLeaves(r->left)+countLeaves(r->right);
    }
    // 查找结点
    BinNode<Elem>* rfindX(Elem x,BinNode<Elem>* r){
        if(!r)   return NULL;
        if(r->data==x)   return r;
        BinNode<Elem>* found;
        found=rfindX(x,r->left);
        return found?found:rfindX(x,r->right);
    }
    // 打印
    void rprint(BinNode<Elem>* r,int depth){
        for(int i=0;i<depth;i++)    cout<<"  ";
        if(!r){
            cout<<"[/]"<<endl;
        }
        else{
            cout<<r->data<<endl;
        rprint(r->left,depth+1);
        rprint(r->right,depth+1);
        }
    }

public:
    BinTree()   {root=NULL;}
    BinTree(Elem r){
        root=new BinNode<Elem>(r);
    }
    ~BinTree(){ };
    void preprint(){
        rpreprint(root);
        cout<<endl;
    }
    void inprint(){
        rinprint(root);
    }
    void postprint(){
        rpostprint(root);
    }
    void print(){
        rprint(root,0);
    }
    BinNode<Elem>* findX(Elem x){
        return rfindX(x,root);
    }
    bool insert(Elem p,int LorR,Elem x){
        BinNode<Elem>* found;
        found=findX(p);
        if(!found)  return false;
        if(LorR==0){
            if(found->left) return false;
            found->left=new BinNode<Elem>(x);
        }
        else{
            if(found->right)    return false;
            found->right=new BinNode<Elem>(x);
        }
        return true;
    }
    // 数叶子结点
    int count(){
        return countLeaves(root);
    }
};

int main(){
    string name;
    // 输入第一个name
    cin>>name;
    BinTree<string> bt(name);
    cin>>name;
    while(name!="-"){
        string  lc,rc;
        cin>>lc>>rc;
        if(lc!="-") bt.insert(name,0,lc);
        if(rc!="-") bt.insert(name,1,rc);
        cin>>name;
    }
    cout<<"叶子结点数目:"<<bt.count()<<endl;
    return 0;
}
/*
Ann
Ann Bill Chris
Bill Daisy Ellen
Chric - Flin
Dasiy - -
Ellen Grace Henry
Flin - -
Grace - -
Henry - -
-
*/


二叉搜索树(Binary Search Tree)

左子树元素比树根小

右子树元素比树根大

左右子树都是BST

BST查找
// 二叉树的头文件
#ifndef bintree_h
#define bintree_h


#include <iostream>
using namespace std;

template<class Elem>
struct BinNode{
    Elem data;
    int h;
    BinNode<Elem>* left;
    BinNode<Elem>* right;
    BinNode(Elem x){
        data=x;
        left=right=NULL;
    }
};

template<class Elem>
class BinTree{
protected:
    BinNode<Elem>* root;
    void rpreprint(BinNode<Elem>* r);
    void rinprint(BinNode<Elem>* r);
    void rpostprint(BinNode<Elem>* r);
    int cntLeaves(BinNode<Elem>* r);
    BinNode<Elem>* rfindX(Elem x,BinNode<Elem>* r);
    void rprint(BinNode<Elem>* r,int depth);
public:
    BinTree()   {root=NULL;}
    BinTree(Elem r){
        root=new BinNode<Elem>(r);
    }
    ~BinTree(){ };
    void preprint(){
        rpreprint(root);
        cout<<endl;
    }
    void inprint(){
        rinprint(root);
    }
    void postprint(){
        rpostprint(root);
    }
    void print(){
        rprint(root,0);
    }
    BinNode<Elem>* findX(Elem x){
        return rfindX(x,root);
    }
    bool insert(Elem p,int LorR,Elem x);
    int cnt(){
        return cntLeaves(root);
    }
};

template<class Elem>
void BinTree<Elem>::rpreprint(BinNode<Elem>* r){   // 对于传指针,一定不要掉以轻心,要首先看一下指针是不是空指针
        if(r==NULL) return;
        cout<<r->data<<" ";
        rpreprint(r->left);
        rpreprint(r->right);
    }

template<class Elem>
void BinTree<Elem>::rinprint(BinNode<Elem>* r){
        if(r==NULL) return;
        rinprint(r->left);
        cout<<r->data<<" ";
        rinprint(r->right);
    }

template<class Elem>
void BinTree<Elem>::rpostprint(BinNode<Elem>* r){
        if(r==NULL) return;
        rinprint(r->left);
        rinprint(r->right);
        cout<<r->data<<" ";
    }

template<class Elem>
int BinTree<Elem>::cntLeaves(BinNode<Elem>* r){
        if(r==NULL) return 0;
        if(r->left==NULL && r->right==NULL) return 1;
        return cntLeaves(r->left)+cntLeaves(r->right);
    }

template<class Elem>
BinNode<Elem>* BinTree<Elem>::rfindX(Elem x,BinNode<Elem>* r){
        if(!r)   return NULL;
        if(r->data==x)   return r;
        BinNode<Elem>* found;
        found=rfindX(x,r->left);
        return found?found:rfindX(x,r->right);
    }

template<class Elem>
void BinTree<Elem>::rprint(BinNode<Elem>* r,int depth){
        for(int i=0;i<depth;i++)    cout<<"  ";
        if(!r){
            cout<<"[/]"<<endl;
        }
        else{
            cout<<r->data<<endl;
        rprint(r->left,depth+1);
        rprint(r->right,depth+1);
        }
    }

template<class Elem>
bool BinTree<Elem>::insert(Elem p,int LorR,Elem x){
        BinNode<Elem>* found;
        found=findX(p);
        if(!found)  return false;
        if(LorR==0){
            if(found->left) return false;
            found->left=new BinNode<Elem>(x);
        }
        else{
            if(found->right)    return false;
            found->right=new BinNode<Elem>(x);
        }
        return true;
    }
#endif // bintree_h


// 二叉搜索树
#include <iostream>
#include "bintree.h"
using namespace std;
// 继承二叉树
template<class Elem>
class BSTree : public BinTree<Elem>{
protected:
	// 查找最大值(递归)
    BinNode<Elem>* rfindMax(BinNode<Elem>* r){
        if(r->right==NULL)  return r;
        return rfindMax(r->right);  // 尾递归
    }
    // 插入
    BinNode<Elem>* rinsert(Elem x,BinNode<Elem>* r){
        if(r==NULL){
            r=new BinNode<Elem>(x);
            if(!r)    throw -1;
        }
        // 如果x是比根结点的小,则向左侧进行插入
        else if(x<r->data)  r->left=rinsert(x,r->left);
        // 如果x是比根结点的大,则向右侧进行插入
        else if(x>r->data)  r->right=rinsert(x,r->right);
        else throw -2;
        return r;
    }
    // 删除(用左子树最大或右子树最小元素代替待删除的结点)
    // 删除左子树最大或者右子树最小
    BinNode<Elem>* rremove(Elem x,BinNode<Elem>* r){
        BinNode<Elem>* tmp;
        if(!r)  throw -1;
        else if(x<r->data){
            r->left=rremove(x,r->left);
        }else if(x>r->data){
            r->right=rremove(x,r->right);
        } else{
            if(r->left && r->right){
            	// 找左子树的最大
                tmp=rfindMax(r->left);
                r->data=tmp->data;
                r->left=rremove(tmp->data,r->left);
            }else{
                tmp=r;
                r=r->left?r->left:r->right;
                delete tmp;
            }
        }
        return r;
    }
public:
    BSTree(){
        this->root=NULL;
    }
    // 返回结点的地址
    BinNode<Elem>* findMax(){
    	// 递归的使用
    	//return rfindMax(this->root);
    	// 把递归改为使用循环(一路向右)因为 右子树元素比树根大
        BinNode<Elem>* tmp=this->root;
        while(tmp && tmp->right){
            tmp=tmp->right;
        }
        return tmp;
    }
    // // 返回结点的地址
    BinNode<Elem>* findMin(){
       // 使用循环(一路向左)因为 左子树元素比树根小
        BinNode<Elem>* tmp=this->root;
        while(tmp && tmp->left){
            tmp=tmp->left;
        }
        return tmp;
    }
    // 查找元素并返回结点的地址
    BinNode<Elem>* findX(Elem x){
    	// 查找是根节点
        BinNode<Elem>* tmp=this->root;
        // x不是根结点时,
        while(tmp && x!=tmp->data){
        	// 如果x小于根结点,则一直向左
            if(x<tmp->data) tmp=tmp->left;
            // 如果x大于根结点,则一直向左
            else    tmp=tmp->right;
        }
        return tmp;
    }
    // 插入
    bool insert(Elem x){
        try{
            this->root=rinsert(x,this->root);
        }catch(int e){
            return false;
        }
        return true;
    }
    // 删除
    bool remove(Elem x){
        try{
            this->root=rremove(x,this->root);
        }catch(int e){
            return false;
        }
        return true;
    }
};
int main(){
    BSTree<int> bt;
    bt.insert(10);
    bt.insert(5);
    bt.insert(20);
    bt.insert(8);
    bt.insert(15);
    bt.insert(2);
    bt.insert(6);
    bt.print();
    cout<<"---------"<<endl;
    bt.remove(10);
    bt.print();
    return 0;
}

平衡二叉树(AVL树)

空树是平衡的,

插入

RR单旋 :与LL单旋对称。

RL双旋:与LR双旋对称。

// 二叉搜索树
#ifndef bstree_h
#define bstree_h

#include <iostream>
#include "bintree.h"
using namespace std;
// 继承二叉树
template<class Elem>
class BSTree : public BinTree<Elem>{
protected:
	// 查找最大值(递归)
    BinNode<Elem>* rfindMax(BinNode<Elem>* r){
        if(r->right==NULL)  return r;
        return rfindMax(r->right);  // 尾递归
    }
    // 插入
    BinNode<Elem>* rinsert(Elem x,BinNode<Elem>* r){
        if(r==NULL){
            r=new BinNode<Elem>(x);
            if(!r)    throw -1;
        }
        // 如果x是比根结点的小,则向左侧进行插入
        else if(x<r->data)  r->left=rinsert(x,r->left);
        // 如果x是比根结点的大,则向右侧进行插入
        else if(x>r->data)  r->right=rinsert(x,r->right);
        else throw -2;
        return r;
    }
    // 删除(用左子树最大或右子树最小元素代替待删除的结点)
    // 删除左子树最大或者右子树最小
    BinNode<Elem>* rremove(Elem x,BinNode<Elem>* r){
        BinNode<Elem>* tmp;
        if(!r)  throw -1;
        else if(x<r->data){
            r->left=rremove(x,r->left);
        }else if(x>r->data){
            r->right=rremove(x,r->right);
        } else{
            if(r->left && r->right){
            	// 找左子树的最大
                tmp=rfindMax(r->left);
                r->data=tmp->data;
                r->left=rremove(tmp->data,r->left);
            }else{
                tmp=r;
                r=r->left?r->left:r->right;
                delete tmp;
            }
        }
        return r;
    }
public:
    BSTree(){
        this->root=NULL;
    }
    // 返回结点的地址
    BinNode<Elem>* findMax(){
    	// 递归的使用
    	//return rfindMax(this->root);
    	// 把递归改为使用循环(一路向右)因为 右子树元素比树根大
        BinNode<Elem>* tmp=this->root;
        while(tmp && tmp->right){
            tmp=tmp->right;
        }
        return tmp;
    }
    // // 返回结点的地址
    BinNode<Elem>* findMin(){
       // 使用循环(一路向左)因为 左子树元素比树根小
        BinNode<Elem>* tmp=this->root;
        while(tmp && tmp->left){
            tmp=tmp->left;
        }
        return tmp;
    }
    // 查找元素并返回结点的地址
    BinNode<Elem>* findX(Elem x){
    	// 查找是根节点
        BinNode<Elem>* tmp=this->root;
        // x不是根结点时,
        while(tmp && x!=tmp->data){
        	// 如果x小于根结点,则一直向左
            if(x<tmp->data) tmp=tmp->left;
            // 如果x大于根结点,则一直向左
            else    tmp=tmp->right;
        }
        return tmp;
    }
    // 插入
    bool insert(Elem x){
        try{
            this->root=rinsert(x,this->root);
        }catch(int e){
            return false;
        }
        return true;
    }
    // 删除
    bool remove(Elem x){
        try{
            this->root=rremove(x,this->root);
        }catch(int e){
            return false;
        }
        return true;
    }
};
// 平衡二叉树是一个二叉搜索树的子类
#include <iostream>
#include "bstree.h"
using namespace std;
template<class Elem>
// 在BinNode的类中加入high 属性
class AVLTree:public BsTree<ELem>{
protected:
	int height(BinNode<Elem>* r){
		if(!r) return -1;
		return r->h;
	}
	// 给定一个结点进行左左旋转
	BinNode<Elem>* LLrotate(BinNode<Elem>* r){
		BinNode<Elem> *child;
		child = r->left;
		r->left = child->right;
		child->right = r;
		r->h = max(height(r->left),height(r->right))+1;
		child->h = max(height(child->left),height(child->right))+1;
		return child;
	}
	// 给定一个结点进行右右旋转
	BinNode<Elem>* RRrotate(BinNode<Elem>* r){
		BinNode<Elem> *child;
		child = r->right;
		r->right = child->left;
		child->left = r;
		r->h = max(height(r->left),height(r->right))+1;
		child->h = max(height(child->left),height(child->right))+1;
		return child;
	}
	// 给定一个结点进行左右旋转
	BinNode<Elem>* LRrotate(BinNode<Elem>* r){
		r->left = RRrotate(r->left);
		return LLrotate(r);
	}
	// 给定一个结点进行右左旋转
	BinNode<Elem>* RLrotate(BinNode<Elem>* r){
		r->right = LLrotate(r->left);
		return  RRrotate(r);
	}
	// 插入
    BinNode<Elem>* rinsert(Elem x,BinNode<Elem>* r){
        if(r==NULL){
            r=new BinNode<Elem>(x);
            if(!r)    throw -1;
        }
        // 如果x是比根结点的小,则向左侧进行插入
        else if(x<r->data){
        	r->left=rinsert(x,r->left);
        	// 判断是否平衡
        	if(height(r->left)-height(r->right) == 2){
        		if(x<r->left->data){
        			r=LLrotate(r);
        		}else{
        			r=LRrotate(r);
        		}
        	}else if(x>r->data){
        		r->right = rinsert(x,r->right);
        		if(height(r->right)-height(r->left) == 2){
        			r=RRrotate(r);
        		}else{
        			r=RLrotate(r);
        		}
        	}else{ throw -2}
        	r->h = max(height(r->left),height(r->right))+1;
        	return r;
        }  
        // 如果x是比根结点的大,则向右侧进行插入
        else if(x>r->data){
         	r->right=rinsert(x,r->right);
        } 
        else throw -2;
        return r;
    }
    
public:
	AVLTree(){
		this->root = NULL;
	}
}
int main(){
	AVLTree<int> t;
	t.insert(30);
	t.insert(20);
	t.print();
	cout << "----" << endl;
	t.insert(10);
	t.print();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37256896/article/details/117073923