【数据结构与算法】动态查找--二叉排序树

基本概念:

二叉排序树也称做二叉查找树。二叉排序树或者是一棵空树;或者是具有下列性质的二叉树:
   (1)若左子树非空,则左子树上所有结点的数据元素值均小于根结点的数据元素值;
   (2)若右子树非空,则右子树上所有结点的数据元素值均大于或等于根结点的数据元素值; 
   (3)左右子树也均为二叉排序树

下图为一棵二叉排序树


二叉排序树的删除算法 :
     删除操作的要求是:首先查找数据元素是否在二叉排序树中存在,若不存在则结束;若存在则按下面四种情况分别进行不同的删除操作。这四种情况是 :
   (1)要删除结点无孩子结点;
   (2)要删除结点只有左孩子结点;
   (3)要删除结点只有右孩子结点;
   (4)要删除结点有左右孩子结点。

对于上述四种不同情况,相应的删除方法是:
(1)要删除结点无孩子结点时,直接删除该结点。
(2)要删除结点只有左孩子结点时,删除该结点且使被删除结点的双亲结点指向被删除结点的左孩子结点。
(3)要删除结点只有右孩子结点时,删除该结点且使被删除结点的双亲结点指向被删除结点的右孩子结点。
(4)要删除结点有左右孩子结点时,分如下三步完成:首先寻找数据元素值大于要删除结点数据元素关键字的最小值,然后把右子树的最左结点的数据元素值拷贝到要删除的结点上;最后删除右子树的最左结点

package cn.ls.find;
/**
 * 
 *结点类
 */
public class BiTreeNode {
	private BiTreeNode leftChild;
	private BiTreeNode rightChild;
	private BiTreeNode parent;
	private int data;

	public BiTreeNode() {
		leftChild = null;
		rightChild = null;
	}

	public BiTreeNode(int item) {
		leftChild = null;
		rightChild = null;
		data = item;
	}

	public BiTreeNode(int item, BiTreeNode left, BiTreeNode right) {
		data = item;
		leftChild = left;
		rightChild = right;
	}

	public void setParent(BiTreeNode parent) {
		this.parent = parent;
	}

	public BiTreeNode getParent() {
		return parent;
	}

	public void setLeftChild(BiTreeNode left) {
		leftChild = left;
	}

	public void setRightChild(BiTreeNode right) {
		rightChild = right;
	}

	public void setData(int data) {
		this.data = data;
	}

	public BiTreeNode getLeft() {
		return leftChild;
	}

	public BiTreeNode getRight() {
		return rightChild;
	}

	public int getData() {
		return data;
	}
}

package cn.ls.find;

import java.util.Vector;

public class BiSearchTree {
	private BiTreeNode root;
	Vector vector = new Vector();

	private void inOrder(BiTreeNode t, Visit vs) {
		if (t != null) {
			inOrder(t.getLeft(), vs);
			vs.print(new Integer(t.getData()));
			inOrder(t.getRight(), vs);
		}
	}

	private void preOrder(BiTreeNode t, Visit vs) {
		if (t != null) {
			vs.print(new Integer(t.getData()));
			preOrder(t.getLeft(), vs);
			preOrder(t.getRight(), vs);
		}
	}

	public BiSearchTree() {
		root = null;
	}

	public void setRoot(BiTreeNode t) {
		root = t;
	}

	public BiTreeNode getRoot() {
		return root;
	}

	public void inOrder(Visit vs) {
		inOrder(root, vs);
	}

	public void preOrder(Visit vs) {
		preOrder(root, vs);
	}

	public BiTreeNode getLeft(BiTreeNode current) {
		return current != null ? current.getLeft() : null;
	}

	public BiTreeNode getRight(BiTreeNode current) {
		return current != null ? current.getRight() : null;
	}
	/**
	 * 查找
	 * @param item
	 * @return
	 */
	public BiTreeNode find(int item) {
		if (root != null) {
			BiTreeNode temp = root;
			while (temp != null) {
				if (temp.getData() == item)
					return temp;// 查找成功

				if (temp.getData() < item)
					temp = temp.getRight(); // 在右子树继续
				else
					temp = temp.getLeft(); // 在左子树继续
			}
		}
		return null; // 查找失败
	}
	/**
	 * 插入
	 * @param ptr
	 * @param item
	 */
	public void insert(BiTreeNode ptr, int item) {
		if (item < ptr.getData()) {
			if (ptr.getLeft() == null) {
				BiTreeNode temp = new BiTreeNode(item); // 生成新结点
				temp.setParent(ptr); // 把ptr结点设为temp结点的父结点
				ptr.setLeftChild(temp); // 把temp结点设为ptr结点的左孩子结点
			} else
				insert(ptr.getLeft(), item); // 在左子树递归
		} else if (item > ptr.getData()) {
			if (ptr.getRight() == null) {
				BiTreeNode temp = new BiTreeNode(item); // 生成新结点
				temp.setParent(ptr); // 把ptr结点设为temp结点的父结点
				ptr.setRightChild(temp); // 把temp结点设为ptr结点的右孩子结点
			} else
				insert(ptr.getRight(), item); // 在右子树递归
		}
		return;
	}
	/**
	 * 删除.
	 * @param ptr
	 * @param item
	 */
	public void delete(BiTreeNode ptr, int item) {
		if (ptr != null) {
			if (item < ptr.getData())
				// 在左子树递归
				delete(ptr.getLeft(), item);
			else if (item > ptr.getData())
				// 在右子树递归
				delete(ptr.getRight(), item);
			else if (ptr.getLeft() != null && ptr.getRight() != null) {
				// 要删除结点寻找到,并且要删除结点左右子树均存在的情况
				BiTreeNode min;
				min = ptr.getRight(); // 取当前结点的右孩子结点
				while (min.getLeft() != null)
					min = min.getLeft(); // min取到最左孩子结点
				ptr.setData(min.getData());// 把min的数据值赋给ptr结点
				delete(ptr.getRight(), min.getData());
				// 在ptr结点的右子树中递归删除min结点
			} else {
				if (ptr.getLeft() == null && ptr.getRight() != null) {
					// 要删除结点寻找到,并且要删除结点只有右子树的情况
					ptr.getParent().setRightChild(ptr.getRight());
					// 让ptr双亲的右孩子指针指向ptr的右孩子结点
					ptr.getRight().setParent(ptr.getParent());
					// 让ptr右孩子的双亲指向ptr的双亲结点
				}

				else if (ptr.getRight() == null && ptr.getLeft() != null) {
					// 要删除结点寻找到,并且要删除结点只有左子树的情况
					ptr.getParent().setLeftChild(ptr.getLeft());
					// 让ptr双亲的左孩子结点指向ptr结点的左孩子结点
					ptr.getLeft().setParent(ptr.getParent());
					// 让ptr左孩子的双亲指向ptr的双亲结点
				}

				else {
					// 要删除结点寻找到,并且要删除结点为叶结点的情况
					BiTreeNode p = ptr.getParent();
					if (p.getLeft() == ptr) // 若要删除结点在双亲的左孩子上
						p.setLeftChild(null); // 把双亲的左孩子置空
					else
						// 若要删除结点在双亲的右孩子上
						p.setRightChild(null); // 把双亲的右孩子置空
				}
			}
		}
	}
}

package cn.ls.find;

public class Visit {
	public void print(Object item) {
		System.out.print(item + "  ");
	}
}

package cn.ls.find;
/**
 * 
 *二叉排序树测试.
 */
public class Exam10_2 {
	public static void main(String[] args) {
		BiSearchTree searchTree = new BiSearchTree();
		int[] a = { 4, 5, 7, 2, 1, 9, 8, 11, 3 };
		int n = 9;
		Visit vs = new Visit();
		BiTreeNode temp = new BiTreeNode(a[0]);

		for (int i = 1; i < n; i++) {
			searchTree.insert(temp, a[i]);
		}
		searchTree.setRoot(temp);

		System.out.println("构造完成后:");
		System.out.print("中序遍历序列为:");
		searchTree.inOrder(vs);
		System.out.print("\n前序遍历序列为:");
		searchTree.preOrder(vs);
		System.out.println();

		System.out.print("查找的数据元素为:");
		System.out.println(searchTree.find(9).getData());

		searchTree.delete(searchTree.getRoot(), 4);
		searchTree.insert(temp, 1);

		System.out.println("删除结点4后:");
		System.out.print("中序遍历序列为:");
		searchTree.inOrder(vs);
		System.out.print("\n前序遍历序列为:");
		searchTree.preOrder(vs);
		System.out.println();
	}
}

结果如下:

构造完成后:
中序遍历序列为:1  2  3  4  5  7  8  9  11  
前序遍历序列为:4  2  1  3  5  7  9  8  11  
查找的数据元素为:9
删除结点4后:
中序遍历序列为:1  2  3  5  7  8  9  11  
前序遍历序列为:5  2  1  3  7  9  8  11  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值