二叉树 讲解

二叉树定义
二叉树是n(n>=0)个结点的有限集合,该集合可能为空集(称为空二叉树),也可能由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成。
在这里插入图片描述
二叉树特点
由二叉树定义以及图示分析得出二叉树有以下特点:
1)每个结点最多有两颗子树,所以二叉树中不存在度大于2的结点。
2)左子树和右子树是有顺序的,次序不能任意颠倒。
3)即使树中某结点只有一棵子树,也要区分它是左子树还是右子树。

二叉树功能代码分享

package p1;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class D {

	public static void main(String[] args) {
		Tree tree = new Tree();
		tree.generateNodes(20);
		System.out.println("tree legal:" + tree.checkNodesLegal(tree.mRoot));
		List<Integer> widthList = new ArrayList<Integer>();
		System.out.println("tree height:" + tree.getTreeHeightWidths(tree.mRoot, 0, widthList));
		System.out.println("tree widths:" + widthList);
		System.out.println(tree);
		System.out.println("111-------------------------------------------------------------------------");
//		System.out.println(tree.searchNode(tree.mRoot, 64));
//		tree.insertNode(new Node(53));
//		System.out.println(tree);
		System.out.println("222-------------------------------------------------------------------------");
//		Node node = tree.searchNode(tree.mRoot, 55);
//		tree.deleteNode(tree.mRoot, node);
//		System.out.println(tree);
		System.out.println("333-------------------------------------------------------------------------");
		Node node = tree.searchNode(tree.mRoot, 64);
		tree.deleteNode(tree.mRoot, node);
		System.out.println(tree);
	}
}

class Tree {
	Node mRoot;
	/**
	 * true,toString()为树中所有节点树状内容;false,toString()为树中所有节点的线性形状内容
	 */
	boolean mTreeStyle = true;

	/**
	 * 生成num个节点
	 * 
	 * @param num 生成的节点个数
	 */
	void generateNodes(int num) {
		Node node;
		Random random = new Random(24);
		mRoot = null;
		for (int i = 0; i < num; i++) {
			node = new Node(random.nextInt(100));
			insertNode(node);
		}
	}
	
	void generateNodes(int[] values) {
		Node node;
		mRoot = null;
		int len = (values == null ? 0 : values.length);
		for (int i = 0; i < len; i++) {
			node = new Node(values[i]);
			insertNode(node);
		}
	}

	/**
	 * 插入一个节点
	 * 
	 * @param node 待插入的节点,不可为null
	 */
	void insertNode(Node node) {
		if (node == null) {
			throw new NullPointerException("node is null");
		}
		if (mRoot == null) {
			mRoot = node;
			return;
		}
		Node cmpNode = mRoot;
		while (true) {
			if (node.value <= cmpNode.value) {
				if (cmpNode.left == null) {
					cmpNode.left = node;
					node.pre = cmpNode;
					break;
				} else {
					cmpNode = cmpNode.left;
				}
			} else {
				if (cmpNode.right == null) {
					cmpNode.right = node;
					node.pre = cmpNode;
					break;
				} else {
					cmpNode = cmpNode.right;
				}
			}
		}
	}

	/**
	 * 查找首个值是value的Node
	 * 
	 * @param node  根节点
	 * @param value 待查找的节点值
	 * @return 如果存在值是value的节点,则返回该节点对象;否则,返回null
	 */
	Node searchNode(Node node, int value) {
		if (node != null) {
			if (node.value == value) {
				return node;
			} else if (value < node.value) {
				return searchNode(node.left, value);
			} else {
				return searchNode(node.right, value);
			}
		}
		return null;
	}

	/**
	 * 查找所有值是value的节点,并存放至list中
	 * 
	 * @param rootNode
	 * @param list
	 * @param value
	 */
	void searchNodes(Node rootNode, List<Node> list, int value) {
		if (list == null) {
			throw new NullPointerException("list is null");
		}
		if (rootNode != null) {
			if (rootNode.value == value) {
				list.add(rootNode);
			}
			if (value <= rootNode.value) {
				searchNodes(rootNode.left, list, value);
			} else {
				searchNodes(rootNode.right, list, value);
			}
		}
	}

	/**
	 * 删除首个值为value的Node
	 * 
	 * @param rootNode
	 * @param value
	 */
	void deleteNode(Node rootNode, int value) {
		Node node = searchNode(rootNode, value);
		if (node != null) {
			deleteNode(rootNode, node);
		}
	}

	/**
	 * 
	 * @param root
	 * @param node
	 */
	void deleteNode(Node root, Node node) {
		if (node == null) {
			throw new NullPointerException("node is null");
		}

		Node preNode = node.pre;
		if (node.left != null && node.right != null) {
			if (preNode == null) { // 如果删除的是根节点
				// 将右侧分支移动至左侧分支的最右侧节点下(因为右节点肯定比左节点大)
				// 也可以将左侧分支移至右侧分支的最左侧节点下
				Node tempNode = node.left;
				while (tempNode.right != null) {
					tempNode = tempNode.right;
				}
				root = node.left;
				mRoot = root;
				node.left.pre = preNode;
				tempNode.right = node.right;
				node.right.pre = tempNode;
				node.destruct();
			} else {
				// 将右侧分支移动至左侧分支的最右侧节点下(因为右节点肯定比左节点大)
				// 也可以将左侧分支移至右侧分支的最左侧节点下
				// --------------------------------------
				// 将node.right的分支移动至node.left的右侧分支的最右侧节点下
				Node tempNode = node.left;
				while (tempNode.right != null) {
					tempNode = tempNode.right;
				}
				tempNode.right = node.right;
				node.right.pre = tempNode;
				// 将移动后的node.left分支移动至node.pre.left的右侧分支的最右侧节点下
				if(preNode.left == node) {
					preNode.left = node.left;
					node.left.pre = preNode;
				} else {
					preNode.right = node.left;
					node.left.pre = preNode;
				}
				node.destruct();
			}
		} else if (node.left != null) {
			if (preNode != null) {
				if (preNode.left == node) {
					preNode.left = node.left;
					node.left.pre = preNode;
					node.destruct();
				} else if (preNode.right == node) {
					preNode.right = node.left;
					node.left.pre = preNode;
					node.destruct();
				}
			} else {
				root = node.left;
				mRoot = root;
				node.destruct();
			}
		} else if (node.right != null) {
			if (preNode != null) {
				if (preNode.left == node) {
					preNode.left = node.right;
					node.right.pre = preNode;
					node.destruct();
				} else if (preNode.right == node) {
					preNode.right = node.right;
					node.right.pre = preNode;
					node.destruct();
				}
			} else {
				root = node.right;
				mRoot = root;
				node.destruct();
			}
		} else {
			if (preNode != null) {
				if (preNode.left == node) {
					preNode.left = null;
					node.destruct();
				} else if (preNode.right == node) {
					preNode.right = null;
					node.destruct();
				}
			} else { // 如果只有一个根节点,并且删除它
				root.pre = null;
				root.left = null;
				root.right = null;
				root = null;
				mRoot = root;
				node.destruct();
			}
		}
	}

	/**
	 * 检查节点合法性
	 * 
	 * @param node 根节点
	 * @return true表示合法;false表示不合法
	 */
	boolean checkNodesLegal(Node node) {
		if (node == null) {
			return true;
		}

		if (node.left != null) {
			Node leftNode = node.left;
			if (leftNode.value > node.value) {
				return false;
			}
		}
		if (node.right != null) {
			Node rightNode = node.right;
			if (rightNode.value <= node.value) {
				return false;
			}
		}

		if (checkNodesLegal(node.left)) {
			return checkNodesLegal(node.right);
		}
		return false;
	}

	/**
	 * 获取根节点rootNode所形成树的结点value最大值
	 * 
	 * @param node
	 * @param value
	 * @return
	 */
	int getMaxValue(Node node, int value) {
		if (node != null) {
			value = node.value;
			int leftValue = getMaxValue(node.left, value);
			int rightValue = getMaxValue(node.right, value);
			if (leftValue > value || rightValue > value) {
				value = (leftValue > rightValue ? leftValue : rightValue);
			}
		}
		return value;
	}

	@Override
	public String toString() {
		String content;
		if (mTreeStyle) {
			content = generateTree(mRoot);
		} else {
			StringBuilder sb = new StringBuilder();
			generateLine(mRoot, sb);
			content = sb.toString();
		}
		return content;
	}

	/**
	 * 生成以node为根节点的线状结构信息,然后保存在sb里
	 * 
	 * @param node
	 * @param sb
	 */
	void generateLine(Node node, StringBuilder sb) {
		if (node != null) {
			sb.append(node.value);
			sb.append(", ");
			generateLine(node.left, sb);
			generateLine(node.right, sb);
			int len = sb.length();
			sb.delete(len - 2, len);
		}
	}

	/**
	 * 生成以node为根节点的树状结构信息内容,然后返回
	 * 
	 * @return
	 */
	String generateTree(Node node) {
		int height = getTreeHeightWidths(node, 0, new ArrayList<Integer>());
		int maxValue = getMaxValue(node, -1);
		int singleLen = String.valueOf(maxValue).length();
		int capacity = 1;
		for (int i = 0; i < height; i++) {
			capacity <<= 1;
		}
		Map<Integer, String> map = new HashMap<Integer, String>(capacity);
		generateTree(node, height - 1, singleLen, 0, 0, map);
		StringBuilder sb = new StringBuilder();
		String value;
		int LeftLen;
		int tempLen;
		int i;
		// 当前行之上的所有节点之和(包括存在的和不存在的)
		int preNum;
		// 当前行应该有多少个节点(包括存在的和不存在的)
		int curRowNum;
		for (int curHeight = 0; curHeight < height; curHeight++) {
			curRowNum = 1;
			for (i = 0; i < curHeight; i++) {
				curRowNum <<= 1;
			}
			preNum = curRowNum - 1;

			for (LeftLen = -1, i = 0; i < curRowNum; i++) {
				value = map.get(preNum + i);
				if (value != null) {
					if (LeftLen == -1) {
						LeftLen = value.length();
					} else {
						tempLen = value.length();
						value = value.substring(LeftLen);
						LeftLen = tempLen;
					}
					sb.append(value);
				}
			}
			sb.append("\n");
		}
		return sb.toString();
	}

	/**
	 * 遍历以node节点为树根的树的所有节点。将value以特定字符串形式存储在map中
	 * 
	 * 
	 * @param node       根节点
	 * @param treeHeight 以node为根节点的树的高度(注意:高度从0开始计数)
	 * @param unitLen    单位字符串长度
	 * @param curHeight  当前节点node在树种的高度(注意:高度从0开始计数)
	 * @param LeftCount  node节点的左侧节点个数
	 * @param map        将各个节点的value值,以特定的字符串存储在map中
	 */
	private void generateTree(Node node, int treeHeight, int unitLen, int curHeight, int LeftCount,
			Map<Integer, String> map) {
		if (node != null) {
			int key = 1;
			for (int i = 0; i < curHeight; i++) {
				key <<= 1;
			}
			key--;
			key += LeftCount;

			String value = String.valueOf(node.value);
			int spaceLen = (1 << (treeHeight - curHeight)) * LeftCount * unitLen
					+ (((1 << (treeHeight - curHeight)) * unitLen - value.length()) >> 1);
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < spaceLen; i++) {
				sb.append(' ');
			}
			sb.append(value);
			map.put(key, sb.toString());

			generateTree(node.left, treeHeight, unitLen, curHeight + 1, LeftCount << 1, map);
			generateTree(node.right, treeHeight, unitLen, curHeight + 1, (LeftCount << 1) + 1, map);
		}
	}

	/**
	 * 获取根节点rootNode所形成树的高度和各层宽度
	 * 
	 * @param rootNode 根节点
	 * @param height   起始计数,从0开始
	 * @param list     各层节点的宽度(个数)
	 * @return 返回值是根节点rootNode所形成树的高度,list里面保存了各层节点的宽度
	 */
	int getTreeHeightWidths(Node rootNode, int height, List<Integer> list) {
		if (list == null) {
			throw new NullPointerException("width list is null");
		}
		if (rootNode != null) {
			height++;
			int size = list.size();
			for (int i = size; i < height; i++) {
				list.add(0);
			}
			int index = height - 1;
			int value = list.get(index);
			list.set(index, ++value);
			int leftHeight = getTreeHeightWidths(rootNode.left, height, list);
			int rightHeight = getTreeHeightWidths(rootNode.right, height, list);
			if (leftHeight > height || rightHeight > height) {
				height = (leftHeight > rightHeight ? leftHeight : rightHeight);
			}
		}
		return height;
	}

}

/**
 * 左侧节点的值小于或者等于该节点的值;右侧节点的值大于该节点的值
 * 
 * @author guigui
 *
 */
class Node {
	int value;
	NodeState state = NodeState.Valid;
	Node pre;
	Node left;
	Node right;

	Node(int value) {
		this.value = value;
	}

	@Override
	public String toString() {
		return "value:" + value;
	}

	void destruct() {
		pre = null;
		left = null;
		right = null;
	}
}

enum NodeState {
	Valid, Invalid
}

代码做过简单测试,如果发现问题,欢迎留言!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值