二叉树(链式、顺序、线索二叉树、二叉排序树、平衡二叉树)


一、链式二叉树

/**
 * 	创建树的节点    -----链式
 * @author Mona
 *
 */
public class TreeNode {
	//节点的权
	int value;
	//左儿子
	TreeNode leftNode;
	//右儿子
	TreeNode rightNode;
	
	public TreeNode(int value) {
		this.value = value;
	}
	
	//设置左儿子
	public void setLeftNode(TreeNode leftNode) {
		this.leftNode = leftNode;
	}
	
	//设置右儿子
	public void setRightNode(TreeNode rightNode) {
		this.rightNode = rightNode;
	}

	//前序遍历
	public void frontShow() {
		//先打印自己的值[先遍历当前结点的内容]
		System.out.println(value);
		//左边node
		if(leftNode != null) {
			leftNode.frontShow();//递归操作可能没有,需在前面添加判断
		}
		//右结点
		if(rightNode != null) {
			rightNode.frontShow();	//递归			//前序遍历输出:1 2 4 5 3 6 7
		}
		
	}

	//中序遍历
	public void midShow() {
		//左结点
		if(leftNode != null) {
			leftNode.midShow();
		}
		//当前结点
		System.out.println(value);
		//右结点
		if(rightNode != null) {
			rightNode.midShow();
		}
	}
	
	//后序遍历
	public void afterShow() {
		// 左结点
		if (leftNode != null) {
			leftNode.afterShow();
		}
		// 右结点
		if (rightNode != null) {
			rightNode.afterShow();
		}
		// 当前结点
		System.out.println(value);
	}
	
	//前序查找                      ------------------->二叉树中的结点查找
	public TreeNode frontSearch(int i) {
		TreeNode target = null;
		//对比当前结点的值
		if(this.value == i) {
			return this;
				//当前结点的值不是要查找的结点
		}else {
			//查找左儿子
			if(leftNode != null) {
				//有可能查得到,也可能查不到,查不到的话,target还是一个null
				target = leftNode.frontSearch(i);
			}
			//如果不为空,说明在左儿子中已经找到
			if(target != null) {
				return target;
			}
			//查找右孩子
			if(rightNode != null) {
				target = rightNode.frontSearch(i);
			}
		}
		return target;
	}

	//中序查找
	public TreeNode middleSearch(int i) {
		TreeNode target = null;
		if(leftNode != null) {
			target = leftNode.middleSearch(i);
		}else {
			if(this.value == i) {
				return this;
			}
			if(rightNode != null) {
				target = rightNode.middleSearch(i);
			}
		}
		return target;
	}

	//删除二叉树的子树
	public void delete(int i) {
		TreeNode parent = this;
		//判断左儿子
		if(parent.leftNode != null && parent.leftNode.value == i) {	//注意判断是否为空
			parent.leftNode = null;
			return ;
		}
		if(parent.rightNode != null && parent.rightNode.value == i) {
			parent.rightNode = null;
			return;
		}
		
		//递归检查并删除左儿子
		parent = leftNode;
		if(parent != null) {
			parent.delete(i);
		}
		
		parent = rightNode;
		if(parent != null) {
			parent.delete(i);
		}
		
	}
}
/**
 *	设置根 
 * @author Mona
 *
 */
public class BinaryTree {
	TreeNode root;
	
	//设置根节点
	public void setRoot(TreeNode root) {
		this.root = root;
	}
	
	//获取根节点
	public TreeNode getRoot() {
		return root;
	}
	
	public void frontShow() {
		if(root != null) {		//删除根结点时使用到的,如果根结点没有了,则不可以进行调用,空指针
			//调root
			root.frontShow();
		}
	}
	
	public void midShow() {
		if(root != null) {
			root.midShow();
		}
	}

	public void afterShow() {
		if(root != null) {
			root.afterShow();
		}
		
	}

	public TreeNode frontSearch(int i) {
		return root.frontSearch(i);
		
	}

	public TreeNode middleSearch(int i) {
		return root.middleSearch(i);
	}

	public void delete(int i) {
		if(root.value == i) {
			root = null;
		}else{
			root.delete(i);
		}
	}
}
/**
 * 	主方法----测试
 * @author Mona
 *
 */
public class TestBinaryTree {
	public static void main(String[] args) {
		//创建一棵树
		BinaryTree binTree = new BinaryTree();
		//创建一个根结点
		TreeNode root = new TreeNode(1);
		binTree.setRoot(root);//把根节点赋给树
		
		TreeNode rootL = new TreeNode(2);//创建一个左节点
		root.setLeftNode(rootL);//把新创建的节点设置为根节点的子结点
		
		TreeNode rootR = new TreeNode(3);///创建一个右结点
		root.setRightNode(rootR);//把新创建的结点设置为根结点的子结点
		
		rootL.setLeftNode(new TreeNode(4));//为第二层的左结点创建两个子结点
		rootL.setRightNode(new TreeNode(5));
		rootR.setLeftNode(new TreeNode(6));//为第二层的右结点创建两个子结点
		rootR.setRightNode(new TreeNode(7));
		
		//前序遍历
		binTree.frontShow();
		System.out.println("---------------------");
		//中序遍历
		binTree.midShow();
		System.out.println("=====================");
		//后序遍历
		binTree.afterShow();
		
		//前序查找
		TreeNode result = binTree.frontSearch(5);
		System.out.println(result);
		
		TreeNode resultm = binTree.middleSearch(4);
		System.out.println(resultm);
		
		System.out.println("==========================");
		
		//删除根结点时,相应的它下面的子左右结点都被删除了
		//删除二叉树中的一个子树
		binTree.delete(2);
		binTree.frontShow();
		
	}
}

二、顺序二叉树

/**
 *	 顺序存储的二叉树---前序遍历
 *		数组形式
 * 
 * @author Mona
 *
 */
public class ArrayBinaryTree {
	
	int[] data;
	
	public ArrayBinaryTree(int[] data) {
		this.data = data;
	}
	
	public void frontShow() {
		frontShow(0);
	}
	
	//前序遍历
	public void frontShow(int index) {
		if(data==null || data.length==0) {
			return;
		}
		System.out.println(data[index]);
		//处理左子树
		if(2*index+1 
public class TestArrayBinaryTree {
	public static void main(String[] args) {
		int[] data = new int[] {1,2,3,4,5,6,7};
		ArrayBinaryTree tree = new ArrayBinaryTree(data);
		tree.frontShow();
	}
}

 

三、线索二叉树

 

二叉树(链式、顺序、线索二叉树、二叉排序树、平衡二叉树)_第1张图片

/**
 * 	创建树的节点
 * @author Mona
 *
 */
public class ThreadedNode {
	//节点的权
	int value;
	//左儿子
	ThreadedNode leftNode;
	//右儿子
	ThreadedNode rightNode;
	
	//标识指针类型
	int leftType;
	int rightType;
	
	public ThreadedNode(int value) {
		this.value = value;
	}
	
	//设置左儿子
	public void setLeftNode(ThreadedNode leftNode) {
		this.leftNode = leftNode;
	}
	
	//设置右儿子
	public void setRightNode(ThreadedNode rightNode) {
		this.rightNode = rightNode;
	}

	//前序遍历
	public void frontShow() {
		//先打印自己的值[先遍历当前结点的内容]
		System.out.println(value);
		//左边node
		if(leftNode != null) {
			leftNode.frontShow();//递归操作可能没有,需在前面添加判断
		}
		//右结点
		if(rightNode != null) {
			rightNode.frontShow();	//递归			//前序遍历输出:1 2 4 5 3 6 7
		}
	}

	//中序遍历
	public void midShow() {
		//左结点
		if(leftNode != null) {
			leftNode.midShow();
		}
		//当前结点
		System.out.println(value);
		//右结点
		if(rightNode != null) {
			rightNode.midShow();
		}
	}
	
	//后序遍历
	public void afterShow() {
		// 左结点
		if (leftNode != null) {
			leftNode.afterShow();
		}
		// 右结点
		if (rightNode != null) {
			rightNode.afterShow();
		}
		// 当前结点
		System.out.println(value);
	}
	
	//前序查找                      ------------------->二叉树中的结点查找
	public ThreadedNode frontSearch(int i) {
		ThreadedNode target = null;
		//对比当前结点的值
		if(this.value == i) {
			return this;
				//当前结点的值不是要查找的结点
		}else {
			//查找左儿子
			if(leftNode != null) {
				//有可能查得到,也可能查不到,查不到的话,target还是一个null
				target = leftNode.frontSearch(i);
			}
			//如果不为空,说明在左儿子中已经找到
			if(target != null) {
				return target;
			}
			//查找右孩子
			if(rightNode != null) {
				target = rightNode.frontSearch(i);
			}
		}
		return target;
	}

	//中序查找
	public ThreadedNode middleSearch(int i) {
		ThreadedNode target = null;
		if(leftNode != null) {
			target = leftNode.middleSearch(i);
		}else {
			if(this.value == i) {
				return this;
			}
			if(rightNode != null) {
				target = rightNode.middleSearch(i);
			}
		}
		return target;
	}

	//删除二叉树的子树
	public void delete(int i) {
		ThreadedNode parent = this;
		//判断左儿子
		if(parent.leftNode != null && parent.leftNode.value == i) {	//注意判断是否为空
			parent.leftNode = null;
			return ;
		}
		if(parent.rightNode != null && parent.rightNode.value == i) {
			parent.rightNode = null;
			return;
		}
		
		//递归检查并删除左儿子
		parent = leftNode;
		if(parent != null) {
			parent.delete(i);
		}
		
		parent = rightNode;
		if(parent != null) {
			parent.delete(i);
		}
		
	}
}
/**
 * 	线索二叉树
 *	设置根 
 * @author Mona
 *
 */
public class BinaryTree {
	ThreadedNode root;
	
	//用于临时存储前驱节点
	ThreadedNode pre = null;

    //遍历线索二叉树
	public void threadIterate() {
		//用于临时存储当前遍历节点
		ThreadedNode node = root;
		while(node != null) {
			//循环找到最开始的节点
			while(node.leftType == 0) {
				node = node.leftNode;
			}
			//打印当前节点的值
			System.out.println(node.value);
			//如果当前节点的右指针指向的是后继节点,可能后继节点还有后继节点
			while(node.rightType == 1) {
				node = node.rightNode;
				System.out.println(node.value);
			}
			//替换遍历的节点
			node = node.rightNode;
		}
	}
	
	// 标识指针类型
	int leftType;
	int rightType;
	
	//设置根节点
	public void setRoot(ThreadedNode root) {
		this.root = root;
	}
	
	//中序线索化二叉树
	public void threadNodes() {
		threadNodes(root);
	}
	
	public void threadNodes(ThreadedNode node) {
		//当前节点如果未null,直接返回
		if(node == null) {
			return;
		}
		
		//处理左子树
		threadNodes(node.leftNode);
		//处理前驱节点
		if(node.leftNode == null) {
			//让当前节点的做指针指向前驱节点
			node.leftNode = pre;
			//改变当前节点左指针的类型
			node.leftType = 1;
		}
		//处理前驱的右指针,如果前驱结点的右指针是null(没有指向右子树)
		if(pre!=null &&pre.rightNode == null) {
			//让前驱结点的右指针指向当前节点
			pre.rightNode = node;
			//改变前驱结点的右指针类型
			pre.rightType = 1;
		}
		
		//每处理一个节点,当前节点是下一个节点的前驱结点
		pre = node;
		
		//处理右子树
		threadNodes(node.rightNode);
	}
	
	//获取根节点
	public ThreadedNode getRoot() {
		return root;
	}
	
	public void frontShow() {
		if(root != null) {		//删除根结点时使用到的,如果根结点没有了,则不可以进行调用,空指针
			//调root
			root.frontShow();
		}
	}
	
	public void midShow() {
		if(root != null) {
			root.midShow();
		}
	}

	public void afterShow() {
		if(root != null) {
			root.afterShow();
		}
		
	}

	public ThreadedNode frontSearch(int i) {
		return root.frontSearch(i);
		
	}

	public ThreadedNode middleSearch(int i) {
		return root.middleSearch(i);
	}

	public void delete(int i) {
		if(root.value == i) {
			root = null;
		}else{
			root.delete(i);
		}
	}
}
/**
 * 	主方法----测试
 * @author Mona
 *
 */
public class TestBinaryTree {
	public static void main(String[] args) {
		//创建一棵树
		BinaryTree binTree = new BinaryTree();
		//创建一个根结点
		ThreadedNode root = new ThreadedNode(1);
		binTree.setRoot(root);//把根节点赋给树
		
		ThreadedNode rootL = new ThreadedNode(2);//创建一个左节点
		root.setLeftNode(rootL);//把新创建的节点设置为根节点的子结点
		
		ThreadedNode rootR = new ThreadedNode(3);///创建一个右结点
		root.setRightNode(rootR);//把新创建的结点设置为根结点的子结点
		
		rootL.setLeftNode(new ThreadedNode(4));//为第二层的左结点创建两个子结点
		
		ThreadedNode fiveNode = new ThreadedNode(5);
		 
		rootL.setRightNode(fiveNode);
		rootR.setLeftNode(new ThreadedNode(6));//为第二层的右结点创建两个子结点
		rootR.setRightNode(new ThreadedNode(7));
		

		//中序遍历树
		binTree.midShow();
		System.out.println("=====================");
		
		//中序线索化二叉树
		binTree.threadNodes();
		
		binTree.threadIterate();
		System.out.println("==============");
		
		//查找5节点的后继节点
		ThreadedNode afterNode = fiveNode.rightNode;
		System.out.println(afterNode.value);
	}
}

 

四、二叉排序树

 

线性结构

顺序存储,不排序:查找困难

顺序存储,排序:删除插入困难

链式存储:无论是否排序  查找困难

 

二叉排序树,也叫二叉查找树、二叉搜索树:BST

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

(1)若左子树不空,则左子树上所有节点的值均小于它的根节点的值;

(2)若右子树不空,则右子树上所有节点的值均大于它的根节点的值;

(3)左、右子树也分别为二叉排序树;

(4)没有键值相等的节点。

 

二叉树(链式、顺序、线索二叉树、二叉排序树、平衡二叉树)_第2张图片

二叉树(链式、顺序、线索二叉树、二叉排序树、平衡二叉树)_第3张图片

public class Node {
	int value;
	Node left;
	Node right;
	
	public Node(int value) {
		this.value = value;
	}

	/**
	 * 	向子树中添加节点
	 * 
	 * @param node
	 */
	public void add(Node node) {
		if(node == null) {
			return;
		}
		
		//判断传入的节点的只比当前子树的根节点的值是大还是小
		//添加的节点比当前节点的值更小
		if(node.value < this.value) {
			//如果左节点为空
			if(this.left == null) {
				this.left = node;
			//如果不为空
			}else {
				this.left.add(node);
			}
		}else {
			if(this.right == null) {
				this.right = node;
			}else {
				this.right.add(node);
			}
		}
	}

	/**
	 * 	中序遍历
	 * 
	 * @param node
	 */
	public void midShow(Node node) {
		if(node == null) {
			return;
		}
		midShow(node.left);
		System.out.println(node.value);
		midShow(node.right);
	}

	/**
	 * 	查找节点
	 * 
	 * @param value2
	 * @return
	 */
	public Node search(int value) {
		if(this.value == value) {
			return this;
		}else if(value < this.value) {
			if(left == null) {
				return null;
			}
			return left.search(value);
		}else {
			if(right == null) {
				return null;
			}
			return right.search(value);
		}
	}

	/**
	 * 	搜索父节点
	 * 
	 * @param value2
	 * @return
	 */
	public Node searchParent(int value) {
		if((this.left!=null && this.left.value==value)||(this.right!=null && this.right.value==value)) {
			return this;
		}else {
			if(this.value>value && this.left!=null) {
				return this.left.searchParent(value);
			}else if(this.value
public class BinarySortTree {
	Node root;
	
	/**
	 * 	向二叉排序树中添加节点
	 * 
	 * @param node
	 */
	public void add(Node node) {
		//如果是一棵空树
		if(root == null) {
			root = node;
		}else {
			root.add(node);
		}
		
	}
	
	/**
	 * 	中序遍历二叉排序树,从小到大的顺序
	 * 
	 */
	public void midShow() {
		if(root != null) {
			root.midShow(root);
		}
	}
	
	/**
	 * 	查找节点的方法
	 * 
	 * @param value
	 * @return
	 */
	public Node search(int value) {
		if(root == null) {
			return null;
		}else {
			return root.search(value);
		}
	}

	/**
	 * 	删除节点
	 * 
	 * @param value
	 * @return
	 */
	public void delete(int value) {
		if(root == null) {
			return;
		}else {
			//找到这个节点
			Node target = search(value);
			//如果没有这个节点
			if(target == null) {
				return;
			}
			//找到他的父节点
			Node parent = searchParent(value);
			//要删除的节点是叶子节点
			if(target.left==null && target.right==null) {
				//要删除的节点是父节点的左子节点
				if(parent.left.value == value) {
					parent.left = null;
					//要删除的节点是父节点的右子节点
				}else {
					parent.right = null;
				}
			//要删除的节点有两个子节点的情况	
			}else if(target.left!=null && target.right!=null){
				//删除右子树中值最小的节点,去获取到该节点的值
				int min = deleteMin(target.right);
				//替换目标节点中的值
				target.value = min;
				
			//要删除的节点有一个左子节点
			}else {
				//有左子节点
				if(target.left != null) {
					//要删除的节点是父节点的左子节点
					if(parent.left.value == value) {
						parent.left = target.left;
						//要删除的节点是夫界定啊的右子节点
					}else {
						parent.right = target.left;
					}
				}
			}
		}
	}
	
	/**
	 * 	删除一棵树中最小的节点
	 * 
	 * @param right
	 * @return
	 */
	private int deleteMin(Node node) {
		Node target = node;
		//递归向左找
		while(target.left != null) {
			target = target.left;
		}
		//删除最小的节点
		delete(target.value);
		return target.value;
	}

	/**
	 * 	搜索父节点
	 * 
	 * @param value
	 * @return
	 */
	public Node searchParent(int value) {
		if(root == null) {
			return null;
		}else {
			return root.searchParent(value);
		}
	}
}
package binary;

public class TestBinarySortTree {
	public static void main(String[] args) {
		int[] arr = new int[] {7,3,10,12,5,1,9};
		//创建一棵二叉树
		BinarySortTree bst = new BinarySortTree();
		//循环添加
		for(int i:arr) {
			bst.add(new Node(i));
		}
		
		//查看树中的值
		bst.midShow();
		
		//查找
//		Node node = bst.search(10);
//		System.out.println(node.value);
		System.out.println("==============");
		
//		Node node2 = bst.search(20);
//		System.out.println(node2);
		
//		Node p1 = bst.searchParent(10);
//		System.out.println(p1.value);
//		System.out.println("--------------");
//		bst.delete(1);
//		bst.midShow();
		bst.delete(7);
		System.out.println("--------");
		bst.midShow();
		
	}
}

 

五、平衡二叉树

 

由于普通的二叉查找树会容易失去“平衡”,极端情况下,二叉查找树会退化成线性的链表,导致插入和查找的复杂度下降到 O(n) ,所以,这也是平衡二叉树设计的初衷。那么平衡二叉树如何保持”平衡“呢?

根据定义,有两个重点,一是左右两子树的高度差的绝对值不能超过1,二是左右两子树也是一颗平衡二叉树。
 

public class Node {
	int value;
	Node left;
	Node right;
	
	public Node(int value) {
		this.value = value;
	}

	/**
	 * 	返回当前节点的高度
	 * 
	 * @return
	 */
	public int height() {
		return Math.max(left==null?0:left.height(), right==null?0:right.height()) +1;
	}
	
	/**
	 * 
	 * 	获取左子树的高度
	 * 
	 * @return
	 */
	public int leftHeight() {
		if(left == null) {
			return 0;
		}
		return left.height();
	}
	
	/**
	 * 	获取右子树的高度
	 * 
	 * 
	 * @return
	 */
	public int rightHeight() {
		if(right == null) {
			return 0;
		}
		return right.height();
	}
	
	
	/**
	 * 	向子树中添加节点
	 * 
	 * @param node
	 */
	public void add(Node node) {
		if(node == null) {
			return;
		}
		
		//判断传入的节点的只比当前子树的根节点的值是大还是小
		//添加的节点比当前节点的值更小
		if(node.value < this.value) {
			//如果左节点为空
			if(this.left == null) {
				this.left = node;
			//如果不为空
			}else {
				this.left.add(node);
			}
		}else {
			if(this.right == null) {
				this.right = node;
			}else {
				this.right.add(node);
			}
		}
		
		//查询是否平衡
		//进行右旋转
		if(leftHeight()-rightHeight() >= 2) {
			//双旋转
			if(left!=null && left.leftHeight()value && this.left!=null) {
				return this.left.searchParent(value);
			}else if(this.value
public class BinarySortTree {
	Node root;
	
	/**
	 * 	向二叉排序树中添加节点
	 * 
	 * @param node
	 */
	public void add(Node node) {
		//如果是一棵空树
		if(root == null) {
			root = node;
		}else {
			root.add(node);
		}
		
	}
	
	/**
	 * 	中序遍历二叉排序树,从小到大的顺序
	 * 
	 */
	public void midShow() {
		if(root != null) {
			root.midShow(root);
		}
	}
	
	/**
	 * 	查找节点的方法
	 * 
	 * @param value
	 * @return
	 */
	public Node search(int value) {
		if(root == null) {
			return null;
		}else {
			return root.search(value);
		}
	}

	/**
	 * 	删除节点
	 * 
	 * @param value
	 * @return
	 */
	public void delete(int value) {
		if(root == null) {
			return;
		}else {
			//找到这个节点
			Node target = search(value);
			//如果没有这个节点
			if(target == null) {
				return;
			}
			//找到他的父节点
			Node parent = searchParent(value);
			//要删除的节点是叶子节点
			if(target.left==null && target.right==null) {
				//要删除的节点是父节点的左子节点
				if(parent.left.value == value) {
					parent.left = null;
					//要删除的节点是父节点的右子节点
				}else {
					parent.right = null;
				}
			//要删除的节点有两个子节点的情况	
			}else if(target.left!=null && target.right!=null){
				//删除右子树中值最小的节点,去获取到该节点的值
				int min = deleteMin(target.right);
				//替换目标节点中的值
				target.value = min;
				
			//要删除的节点有一个左子节点
			}else {
				//有左子节点
				if(target.left != null) {
					//要删除的节点是父节点的左子节点
					if(parent.left.value == value) {
						parent.left = target.left;
						//要删除的节点是夫界定啊的右子节点
					}else {
						parent.right = target.left;
					}
				}
			}
		}
	}
	
	/**
	 * 	删除一棵树中最小的节点
	 * 
	 * @param right
	 * @return
	 */
	private int deleteMin(Node node) {
		Node target = node;
		//递归向左找
		while(target.left != null) {
			target = target.left;
		}
		//删除最小的节点
		delete(target.value);
		return target.value;
	}

	/**
	 * 	搜索父节点
	 * 
	 * @param value
	 * @return
	 */
	public Node searchParent(int value) {
		if(root == null) {
			return null;
		}else {
			return root.searchParent(value);
		}
	}
}
	public static void main(String[] args) {
		//int[] arr = new int[] {8,9,6,7,5,4};
		//int[] arr = new int[] {2,1,4,3,5,6};
		int[] arr = new int[] {8,9,5,4,6,7};
		
		
		//创建一棵二叉树
		BinarySortTree bst = new BinarySortTree();
		//循环添加
		for(int i:arr) {
			bst.add(new Node(i));
		}
		
		//查看高度
		System.out.println(bst.root.height());
		
		//没旋转前是8,旋转之后是6,结果正确
		System.out.println(bst.root.value);
		
	}
}

 

 

 

你可能感兴趣的:(数据结构--代码Java版)