把二元查找树转变成排序的双向链表[数据结构]

5 篇文章 0 订阅

题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。

  比如将二元查找树
   
                                        10
                                          /    \
                                        6       14
                                      /  \     /  \
                                    4     8  12    16
转换成双向链表

4=6=8=10=12=14=16

  分析:本题是微软的面试题。很多与树相关的题目都是用递归的思路来解决,本题也不例外。下面我们用两种不同的递归思路来分析。

  思路一:当我们到达某一结点准备调整以该结点为根结点的子树时,先调整其左子树将左子树转换成一个排好序的左子链表,再调整其右子树转换右子链表。最近链接左子链表的最右结点(左子树的最大结点)、当前结点和右子链表的最左结点(右子树的最小结点)。从树的根结点开始递归调整所有结点。

  思路二:我们可以中序遍历整棵树。按照这个方式遍历树,比较小的结点先访问。如果我们每访问一个结点,假设之前访问过的结点已经调整成一个排序双向链表,我们再把调整当前结点的指针将其链接到链表的末尾。当所有结点都访问过之后,整棵树也就转换成一个排序双向链表了。

 

参考网址:http://zhedahht.blog.163.com/blog/static/254111742007127104759245/

在此附上思路二的java实现:

//树节点类,包含节点的值,节点的左孩子、右孩子和父节点 
public class TreeNode {
	private int key;
	private TreeNode leftchlid;
	private TreeNode rightchild;
	private TreeNode parent;
	public int getKey() {
		return key;
	}
	public void setKey(int key) {
		this.key = key;
	}
	public TreeNode getLeftchlid() {
		return leftchlid;
	}
	public void setLeftchlid(TreeNode leftchlid) {
		this.leftchlid = leftchlid;
	}
	public TreeNode getRightchild() {
		return rightchild;
	}
	public void setRightchild(TreeNode rightchild) {
		this.rightchild = rightchild;
	}
	public TreeNode getParent() {
		return parent;
	}
	public void setParent(TreeNode parent) {
		this.parent = parent;
	}
	//构造函数
	public  TreeNode(int key,TreeNode leftchild,TreeNode rightchild,TreeNode parent){
		this.key= key;
		this.leftchlid= leftchild;
		this.rightchild= rightchild;
		this.parent= parent;
		
	}
}


//二叉排序树类
public class BSTree {
	private TreeNode root = null;

	public TreeNode getRoot() {
		return root;
	}

	public void setRoot(TreeNode root) {
		this.root = root;
	}
	//将值key插入到二叉排序树中 
	public void insert(int key) {
		TreeNode newnode = new TreeNode(key, null, null, null);
		TreeNode parentnode = null;
		TreeNode pnode = root;
		if (root == null) {
			root = newnode;
			return;
		}
		while (pnode != null) {
			parentnode = pnode;
			if (key < pnode.getKey()) {
				pnode = pnode.getLeftchlid();
			} else if (key > pnode.getKey()) {
				pnode = pnode.getRightchild();
			} else {
				// 树中已经有该值,直接返回
				return;
			}

		}
		if (key < parentnode.getKey()) {
			parentnode.setLeftchlid(newnode);
			newnode.setParent(parentnode);
		} else {
			parentnode.setRightchild(newnode);
			newnode.setParent(parentnode);
		}
	}
	/*搜索关键字为key的节点,如果该节点不再二叉树中,返回null,
	 *否则返回关键字为key的节点 
	 */
	public TreeNode search(int key) {
		TreeNode pnode = root;

		while (pnode != null && pnode.getKey() != key) {
			if (key < root.getKey()) {
				pnode = pnode.getLeftchlid();
			} else if (key > pnode.getKey()) {
				pnode = pnode.getRightchild();
			}
		}
		return pnode;
			

	}

	/*
	 * 返回以node节点为根节点的子树中key值最小的节点
	 */
	public TreeNode minElem(TreeNode node) {
		if (root == null || node == null) {
			return null;
		}
		while (node.getLeftchlid() != null) {
			node = node.getLeftchlid();
		}
		return node;

	}

	/*
	 * 返回以node节点为根节点的子树中key值最大的节点
	 */
	public TreeNode maxElem(TreeNode node) {
		if (root == null || node == null) {
			return null;
		}
		while (node.getRightchild() != null) {
			node = node.getRightchild();
		}
		return node;
	}

	/*
	 * 返回中序遍历中node节点的前驱节点
	 */
	public TreeNode precessor(TreeNode node) {
		if (node == null || root == null) {
			return null;
		}
		// 先判断该节点有没有左孩子,如果有做孩子,则返回maxElem(node.getleftchild()),如果
		// 没有左孩子,再判断该节点是不是父节点的右孩子,如果是,则返回父节点,
		// 如果不是,则找到该节点的某个祖先节点,该祖先节点是自己父节点的右孩子,返回该祖先节点的父节点
		TreeNode parentnode = node.getParent();

		if (node.getLeftchlid() != null) {
			return maxElem(node.getLeftchlid());
		}
		if (parentnode.getRightchild() == node) {
			return parentnode;
		}
		while (parentnode != null && parentnode.getLeftchlid() == node) {
			node = parentnode;
			parentnode = parentnode.getParent();
		}
		return parentnode;
	}

	/*
	 * 返回中序遍历中node节点的后继节点
	 */
	public TreeNode successor(TreeNode node) {
		if (node == null || root == null) {
			return null;
		}
		TreeNode parentnode = node.getParent();
		// 如果节点有右孩子,则返回minElem(node.getrightchild()),如果
		// 没有右孩子,再判断该节点是不是父节点的左孩子,如果是,则返回父节点
		// 如果不是,则找到该节点的某个祖先节点,该祖先节点是自己父节点的左孩子
		if (node.getRightchild() != null) {
			return minElem(node.getRightchild());
		}
		if (node == parentnode.getLeftchlid()) {
			return parentnode;
		}
		while (parentnode != null && node == parentnode.getRightchild()) {
			node = parentnode;
			parentnode = parentnode.getParent();
		}
		return parentnode;
	}
	//删除节点
	public void delete(TreeNode node){
		//判断要删除的节点或根节点是否为空
		if(node == null){
			//System.out.println("");
			return;
		}
		TreeNode parentnode = node.getParent();
		//该节点的左孩子和右孩子都为空
		if(node.getLeftchlid() == null&&node.getRightchild() == null){
			if(parentnode.getLeftchlid() == node)//该节点为父节点的左孩子
			{
				parentnode.setLeftchlid(null);
			}
			else
				parentnode.setRightchild(null);
			return;
		}
		//该节点的左孩子为空,右孩子不为空
		if(node.getLeftchlid() == null&&node.getRightchild()!=null){
			if(parentnode.getLeftchlid() == node)//该节点为父节点的左孩子
			{
				parentnode.setLeftchlid(node.getRightchild());
				node.getRightchild().setParent(parentnode);
			}
			else //该节点为父节点的右孩子
			{
				parentnode.setRightchild(node.getRightchild());
				node.getRightchild().setParent(parentnode);
			}
			return;
		}
		//该节点的右孩子为空,左孩子不为空
		if(node.getLeftchlid()!=null&&node.getRightchild()==null){
			if(parentnode.getLeftchlid()==node)//该节点为父节点的左孩子
			{
				parentnode.setLeftchlid(node.getLeftchlid());
				node.getLeftchlid().setParent(parentnode);
			}
			else该节点为父节点的右孩子
			{
				parentnode.setRightchild(node.getLeftchlid());
				node.getLeftchlid().setParent(parentnode);
			}
			return;
		}
		//该节点的左孩子和右孩子都不为空
		TreeNode successornode = successor(node);
		delete(successornode);
		node.setKey(successornode.getKey());
	}
	
	public void delete(int key) {
		TreeNode findnode = search(key);
		if(findnode == null){
			System.out.println("不存在该节点!");
			return;
		}
		else 
		{
			delete(findnode);
		}
	}
	// 调整指针节点
	public void convertToDoubleList(TreeNode currentnode){
		TreeNode headnode = null;//指向循环列队头结点
		TreeNode indexnode = null;//指向前一个节点
		
		currentnode.setLeftchlid(indexnode);
		if(indexnode == null){
			headnode = currentnode;
		}
		else{
			indexnode.setRightchild(currentnode);
		}
		indexnode = currentnode;
		System.out.println(currentnode.getKey());
	}
	//中序遍历
	public void inOrderBSTree(TreeNode root){
		if(root == null){
			return;
		}
		if(root.getLeftchlid()!=null){
			inOrderBSTree(root.getLeftchlid());
		}
		convertToDoubleList(root);
		
		if(root.getRightchild()!=null){
			inOrderBSTree(root.getRightchild());
		}
	}

}


public class Test {
	public static void main(String[] args)  {
		BSTree tree = new BSTree();
		int[] array = {10,6,8,12,14,4,16};
		for(int i =0;i<array.length;i++){
			tree.insert(array[i]);
		}
		tree.inOrderBSTree(tree.getRoot());
		//tree.delete(12);
		//tree.inOrderBSTree(tree.getRoot());

	}

}


测试结果:

4
6
8
10
12
14
16
 

		

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值