二叉树定义
二叉树是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
}
代码做过简单测试,如果发现问题,欢迎留言!