树和二叉树

关于树的介绍

可参考树的基本知识,以下是对其的简述
是一些结点的集合。若非空树,则由根节点和0个或多个非空的子树组成
路径是结点和另一个结点之间边和结点的序列
结点的度指的是结点拥有的子树数,树的度是树内各结点的度的最大值
结点的高度指的是该结点到叶子结点最长路径边的总和
结点的深度指的是该结点到根节点最长路径边的总和
在这里插入图片描述
在这里插入图片描述

二叉树

二叉树的基本概念

二叉树是一个每个根节点最多只能有两个分支的树,左边的分支称之为左子树,右边的分支称之为右子树。二叉树节点的度最大也就是2,而普通的树,节点的度是没有限制的。

二叉树的分类

完美/满二叉树(Perfect Binary Tree)
完美二叉树满足两个特性:

  • 所有的结点都包含两个子结点
  • 所有的叶子节点的Height或者Level都相等

完全二叉树(Complete Binary Tree)

  • 完全二叉树是除了最后一层都是满的(都有两个子节点),并且最后一层的节点是从左往右排列的。
  • 如果最后一层排满了就是完美二叉树,没有满则是完全二叉树。
  • 完美二叉树一定是完全二叉树完全二叉树不一定是完美二叉树
    一个完全二叉树可以高效的使用数组来表示。

完满二叉树(Full Binary Tree)
每个节点都有两个子节点。它比完美二叉树少了所有叶子结点的高度相等这个条件。

二叉树的性质

  • 二叉树的第i层上至多有2^(i-1)个结点
  • 深度为k的二叉树至多有2^k-1个结点
  • 对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1
  • 具有n个结点的完全二叉树的深度为floor(log2n)+1
  • 如果对一棵有n个结点的完全二叉树(其深度为floor(log2n)+1)的结点按层序编号(从第1层到第floor(log2n)+1层,每层从左到右)对任一结点i,有:
    (1)如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点floor(i/2)
    (2)如果2i>n,则结点i无左孩子(结点i是叶子结点),否则其左孩子是结点2i
    (3)如果2i+1>n,则结点i无右孩子(结点i是叶子结点),否则其右孩子是结点2i+1

Java实现

二叉树的顺序存储

数组实现一个简单的二叉树:

public class ArrayBinaryTree<T> {
    private static final int DEFAULT_DEEP = 5;
    private int deep;
    private int capacity;
    private Object[] nodes;

    public ArrayBinaryTree() {
        this(DEFAULT_DEEP);
    }

    public ArrayBinaryTree(int deep) {
        this.deep = deep;
        nodes = new Object[capacity = (int) Math.pow(2, deep) - 1];
    }

    public ArrayBinaryTree(int deep, T rootData) {
        this(deep);
        nodes[0] = rootData;
    }

    public void add(int parentIndex, T data, boolean left) {
        if (data == null) {
            throw new NullPointerException();
        }
        if (nodes[parentIndex] == null) {
            throw new NoSuchElementException();
        }

        if (left) {
            nodes[parentIndex * 2 + 1] = data;
        } else {
            nodes[parentIndex * 2 + 2] = data;
        }
    }

    public boolean isEmpty() {
        return nodes[0] == null;
    }

    /**
     * 获取索引为index节点的父节点
     *
     * @param index
     * @return
     */
    public T getParent(int index) {
        if (index == 0) {
            return null;
        }

        return (T) nodes[(index - 1) / 2];
    }

    /**
     * 获取索引为index的右节点
     *
     * @param index
     * @return
     */
    public T getRight(int index) {
        if (2 * index + 2 >= capacity) {
            return null;
        }
        return (T) nodes[index * 2 + 2];
    }

    /**
     * 获取索引为index的左节点
     *
     * @param index
     * @return
     */
    public T getLeft(int index) {
        if (2 * index + 1 >= capacity) {
            return null;
        }
        return (T) nodes[2 * index + 1];
    }

    public T getRoot() {
        return (T) nodes[0];
    }

    public int indexOf(T data) {
        for (int i = 0; i < capacity; i++) {
            if (nodes[i].equals(data)) {
                return i;
            }
        }
        return -1;
    }
}

这种顺序存储结构仅适用于完全二叉树。因为最坏情况下,一个深度为k且只有k个结点的单支树需要2^k-1的一维数组,不存在的结点用0表示。

二叉树的链式存储

二叉链表实现一个简单的二叉树。链表的每个Node包含三个域:left和right指针域以及数据域

public class TwoLinkedBinaryTree<T> {

    class Node {
        Object data;
        Node left;
        Node right;

        public Node() {
        }
        public Node(Object data) {
            this.data = data;
        }

        public Node(Object data, Node left, Node right) {
            this.data = data;
            this.left = left;
            this.right = right;
        }

        @Override
        public String toString() {
            return data + "";
        }
    }
    private Node root;
    public TwoLinkedBinaryTree() {
        this.root = new Node();
    }

    public TwoLinkedBinaryTree(T data) {
        this.root = new Node(data);
    }

    public Node addNode(Node parent, T data, boolean left) {
        if (data == null) {
            throw new NullPointerException();
        }

        if (parent == null) {
            throw new IllegalStateException("节点为null,不能添加子节点");
        }

        if (left && parent.left != null) {
            throw new IllegalStateException(parent + "节点已经存在左节点");
        }

        if (!left && parent.right != null) {
            throw new IllegalStateException(parent + "节点已经存在右节点");
        }

        Node node = new Node(data);
        if (left) {
            parent.left = node;
        } else {
            parent.right = node;
        }
        return node;
    }

    public boolean isEmpty() {
        return root.data == null;
    }

    public Node getRoot() {
        return root;
    }

    public T getLeft(Node parent) {
        return parent == null ? null : (T) parent.left.data;
    }

    public T getRight(Node parent) {
        return parent == null ? null : (T) parent.right.data;
    }
    
    public int deep() {
        return deep(root);
    }

    public int deep(Node node) {
        if (node == null) {
            return 0;
        }

        if (node.left == null && node.right == null) {
            return 1;
        }

        int left = deep(node.left);
        int right = deep(node.right);
        //记录其所有左、右子树较大的深度
        int max = left > right ? left : right;
        //返回其左右子树中较大深度+1
        return max + 1;
    }
    public static void main(String[] args) {
        TwoLinkedBinaryTree<String> binaryTree = new TwoLinkedBinaryTree<>("0");
        TwoLinkedBinaryTree<String>.Node left = binaryTree.addNode(binaryTree.getRoot(), "1", true);
        TwoLinkedBinaryTree<String>.Node right = binaryTree.addNode(binaryTree.getRoot(), "2", false);
        binaryTree.addNode(left, "3", true);
        binaryTree.addNode(left, "4", false);
        binaryTree.addNode(right, "5", true);
        binaryTree.addNode(right, "6", false);
        System.out.println("tree deep = " + binaryTree.deep());
        System.out.println(left + "的左节点: " + binaryTree.getLeft(left));
        System.out.println(left + "的右节点: " + binaryTree.getRight(left));
    }
}

三叉链表实现一个简单的二叉树。链表的每个Node包含四个域:left、right和parent指针域以及数据域

public class ThreeLinkedBinaryTree<T> {
    public static class Node {
        Object data;
        Node left;
        Node right;
        Node parent;
        public Node() {
        }

        public Node(Object data) {
            this.data = data;
        }

        public Node(Object data, Node left, Node right, Node parent) {
            this.data = data;
            this.left = left;
            this.right = right;
            this.parent = parent;
        }
        
        @Override
        public String toString() {
            return data + "";
        }
    }
    private Node root;
    public ThreeLinkedBinaryTree() {
        this.root = new Node();
    }

    public ThreeLinkedBinaryTree(T data) {
        this.root = new Node(data);
    }

    public Node addNode(Node parent, T data, boolean left) {
        if (data == null) {
            throw new NullPointerException();
        }

        if (parent == null) {
            throw new IllegalStateException("节点为null,不能添加子节点");
        }

        if (left && parent.left != null) {
            throw new IllegalStateException(parent + "节点已经存在左节点");
        }

        if (!left && parent.right != null) {
            throw new IllegalStateException(parent + "节点已经存在右节点");
        }

        Node node = new Node(data);
        if (left) {
            parent.left = node;
        } else {
            parent.right = node;
        }
        node.parent = parent;
        return node;
    }

    public boolean isEmpty() {
        return root.data == null;
    }

    public T getParent(Node node) {
        if (node == null) {
            throw new NullPointerException();
        }
        return (T) node.parent.data;
    }

    public T getLeft(Node parent) {
        if (parent == null) {
            throw new NullPointerException();
        }
        return (T) parent.left.data;
    }

    public T getRight(Node parent) {
        if (parent == null) {
            throw new NullPointerException();
        }
        return (T) parent.right.data;
    }

    public Node getRoot() {
        return root;
    }

    public int deep() {
        return deep(root);
    }


    public int deep(Node node) {
        if (node == null) {
            return 0;
        }

        if (node.left == null && node.right == null) {
            return 1;
        }

        int left = deep(node.left);
        int right = deep(node.right);
        //记录其所有左、右子树较大的深度
        int max = left > right ? left : right;
        //返回其左右子树中较大深度+1
        return max + 1;
    }

    public static void main(String[] args) {
        ThreeLinkedBinaryTree<String> binaryTree = new ThreeLinkedBinaryTree<>("0");
        Node left = binaryTree.addNode(binaryTree.getRoot(), "1", true);
        Node right = binaryTree.addNode(binaryTree.getRoot(), "2", false);
        binaryTree.addNode(left, "3", true);
        binaryTree.addNode(left, "4", false);
        binaryTree.addNode(right, "5", true);
        binaryTree.addNode(right, "6", false);
        System.out.println("tree deep = " + binaryTree.deep());
        System.out.println(left + "的左节点: " + binaryTree.getLeft(left));
        System.out.println(left + "的右节点: " + binaryTree.getRight(left));
        System.out.println(left + "的父节点: " + binaryTree.getParent(left));
    }
}

二叉树的遍历

树的遍历主要有两种,一个是深度优先遍历,一个是广度优先遍历。

深度优先遍历又有三种:先序、中序、后序遍历。先序、中序、后序遍历区别在于访问根节点和遍历左右子树的先后关系

先序遍历:先访问根结点,再先序遍历左子树,最后先序遍历右子树

private void preorder(Node<T> node) {
	if (node == null) {
		return;
	}
	System.out.println(node.value);//先访问根结点
	preorder(node.left);
	preorder(node.right);
}

中序遍历:先中序遍历左子树,再访问根节点,最后中序遍历右子树

private void inorder(Node<T> node) {
	if (node == null) {
		return;
	}
	inorder(node.left);
	System.out.println(node.value);//中间访问根节点
	inorder(node.right);
}

后序遍历:后序遍历左子树,再后序遍历右子树,最后访问根结点

private void postorder(Node<T> node) {
	if (node == null) {
		return;
	}
	postorder(node.left);
	postorder(node.right);
	System.out.println(node.value);//最后访问根节点
}

广度优先遍历也叫按层遍历(一层一层的遍历节点):

public void levelorder() {
	if (root == null)
		return;
	Deque<Node<T>> queue = new ArrayDeque<>();
	queue.addLast(root);
	while (!queue.isEmpty()) {
		Node<T> node = queue.removeFirst();
		System.out.println(node.value);
		if (node.left != null) {
			queue.addLast(node.left);
		}
		if (node.right != null) {
			queue.addLast(node.right);
		}
	}
}

C实现

#include<iostream>
#include<stdlib.h> 
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10 
using namespace std;
typedef  struct BiTNode
{
	char  data;
	struct BiTNode *lchild , *rchild;  //左、右孩子指针 
} BiTNode , *BiTree;
 
bool  CreateBiTree(BiTree &T)
{
	//按先序序列输入二叉树中的节点值,空格代表空字符 
	char ch; //接收输入的字符
	cout<<"先序输入字符"<<endl; 
	cin>>ch;
	if(ch == ' ')  T = NULL;
	else
	{
		if(! (T = (BiTNode*) malloc (sizeof(BiTNode))))	  return false;
		T->data = ch;
		CreateBiTree(T->lchild) ; //构造左子树
		CreateBiTree(T->rchild) ;//构造右子树 
	}
	return true;
}

/**********************这里构造一个栈 , 中序遍历需要栈 ********************************************/
typedef  struct 
{
	BiTree *base;
	BiTree *top; 
	int stacksize; //当前以分配的存储空间 , 以元素为单位 
}SqStack;
 
bool InitStack(SqStack s)
{
	s.base =  (BiTree *)  malloc( STACK_INIT_SIZE * sizeof(BiTree));
	if(!s.base) return false; //存储分配失败
	s.top = s.base;
	s.stacksize = STACK_INIT_SIZE;
	return true; 
}
 
bool  Push(SqStack &s , BiTree e)
{
	if(s.top - s.base >= s.stacksize) {  //栈满,追加存储空间 
		s.base = (BiTree *) realloc(s.base , (s.stacksize + STACKINCREMENT) * sizeof(BiTree));
		if(!s.base)  return false;
		s.top = s.base + s.stacksize;
		s.stacksize += STACKINCREMENT;
	} 
	*s.top ++ = e;
	return true;
}
 
bool  Pop(SqStack &s , BiTree &e)
{
	if(s.top == s.base )  return false;  //栈空
	e = * --s.top;
	return true; 
}
bool StackEmpty(SqStack s)
{
	if(s.base == s.top) return true;
	else
	{
		return false;
	}
}
bool visit(BiTree e)  //将二叉树的节点显示到控制台上 
{
	cout<<e->data;
	return true;
}
SqStack s;  //定义栈头结点 
/*******************以上栈的构造完毕 ****************************/
 
//中序遍历 
bool InOrderTraverse(BiTree T , bool  (*visit)(BiTree e)) //后一个参数为接收visit函数指针 
{
	cout<<"中序遍历二叉树结果如下:"<<endl; 
	InitStack(s); 
	BiTree p ; p=T;
	while(p || !StackEmpty(s))
	{
		if(p)
		{
			Push(s , p) ; p = p->lchild;  //根指针进栈 , 遍历左子树 
		}
		else
		{
			//根指针退栈, 访问根节点 ,遍历右子树
			Pop(s , p); 
			cout<<p->data;
			p = p->rchild;
		}
	}
	return true;
}

//先序遍历
bool PreOrderTracerse(BiTree T , bool (*visit)(BiTree e)) 
{
	if(T)
	{
		if( (*visit)(T))
			if(PreOrderTracerse(T->lchild , visit))
				if(PreOrderTracerse(T->rchild , visit))  return true;
		return false;
	}
	else return true;
}
 
//后序遍历
bool PosOrderTracerse(BiTree T , bool (*visit)(BiTree e)) 
{
	if(T)
	{
	
		if(PosOrderTracerse(T->lchild , visit))
			if(PosOrderTracerse(T->rchild ,visit))
				if((*visit)(T))  return true;
		return false;
	}
	else return true;
}
//层次遍历
void LevelTracerse(BiTree T , bool (*visit)(BiTree e)) 
{
	queue<BiTree> q;
	if(T==NULL)
	{
		return;
	}
	q.push(T);
	while(!q.empty()){
		BiTree front=q.front();
		if(front->lchild){
			q.push(front->lchild)
		}
		if(front->rchild){
			q.push(front->rchild)
		}
		cout<<front->data;
	}
}

int  main()
{
	//定义一个visit函数指针
	bool (*visit_point) (BiTree e);
	visit_point = visit;
	BiTree T;
	CreateBiTree(T) ;
	cout<<"二叉树构造完成!"<<endl<<endl<<endl; 
	InOrderTraverse(T , visit_point); 
	cout<<endl;
	cout<<"先序遍历结果如下:"<<endl;
	PreOrderTracerse(T , visit_point) ;
	cout<<endl;
	cout<<"后序遍历结果如下:"<<endl;
	PosOrderTracerse(T , visit_point);
	return true;
}

C++详细实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值