树---二叉树
一:数的概念
1.数是一种特殊的数据结构,它可以用来描述有分支的结构,是由一个或者一个以上的节点所组成的有限的集合。
2.结点的度:结点拥有子树的个数。
3.树的度:树中所有结点的度的最大值。
4.叶结点:度为0的结点,也成为终端结点。
5.子结点:结点子数的根(即直接后继)称为该结点的子结点。
6.双亲节点:结点是其子树的双亲。
7.兄弟结点:同一双亲孩子结点之间互称兄弟结点。
8.结点的层次:结点的层次从树根开始定义,根为第一层,根的孩子为第二层,若某结点在第k层,则其孩子就在第k+1层,以此类推。
9:树的形态:
二:二叉数
1.概念
由一个由有限节点所组成的集合,此集合可以为空集合,或由一个树根及左右两个子树所组成。简单地说,二叉树最多只能有两个子节点,就是度小于或等于2。
2.满二叉树
如果二叉树的高度为h,树的节点树为2h-1, h>=0,则称之为“满二叉树”
3.完全二叉树
4.二叉树的性质
1)在二叉树的第n层上至多有2的(n-1)次方 个节点
2)深度为K的二叉树至多有2的k次方减1个节点
3)具有n个节点的完全二叉树的深度K为:
K = log2n+1
三:二叉查找树
1.其左子树(left subtree)下的每个后代节点(descendant node)的值都小于节点 n 的值;
2.其右子树(right subtree)下的每个后代节点的值都大于节点 n 的值
构建二叉查找树
定义结点:
/**
* bst树的节点
*/
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val, TreeNode left, TreeNode right) { // 构造方法
this.val = val;
this.left = left;
this.right = right;
}
@Override
public String toString() {
return "TreeNode [val=" + val + ", left=" + left + ", right=" + right + "]";
}
}
1.迭代法创建
public class BST {
private TreeNode root; // 根
private int size; // 容量大小
public TreeNode getRoot() {
return this.root;
}
/**
* 添加操作--add (迭代法创建树)
*
* @param val
*/
public void add(int val) {
TreeNode tmp = new TreeNode(val, null, null);
if (this.root == null) { // 空树时
root = tmp;
this.size++;
} else { // 不为空时
TreeNode curr = root;
while (true) {
if (val < curr.val) { // 左子树
if (curr.left == null) { // 为空时挂节点
curr.left = tmp;
this.size++;
break;
}
curr = curr.left;// 继续往左移动
} else if (val > curr.val) { // 右子树
if (curr.right == null) {
curr.right = tmp;
this.size++;
break;
}
curr = curr.right; // 继续往右走
}
}
}
}
测试:
@Test
public void test() {
BST tree = new BST();
tree.add(6);
tree.add(3);
tree.add(8);
tree.add(7);
tree.add(2);
tree.add(4);
System.out.println(tree);
//结果>>>BST [root=TreeNode [val=6, left=TreeNode [val=3, left=TreeNode [val=2, left=null, right=null], right=TreeNode [val=4, left=null, right=null]], right=TreeNode [val=8, left=TreeNode [val=7, left=null, right=null], right=null]], size=6]
2.递归法创建
/**
* 递归法--创建树
*
* @param root
* @return
*/
public TreeNode insert(TreeNode curr, int val) {
if (curr == null) { // 终止条件
return new TreeNode(val, null, null);
} else if (val < curr.val) { // 左子树
curr.left = insert(curr.left, val);
} else if (val > curr.val) { // 右子树
curr.right = insert(curr.right, val);
}
return curr;
}
测试:
/**
* 递归测试
*/
BST tree = new BST();
TreeNode root = tree.getRoot();
root = tree.insert(root, 6);
root = tree.insert(root, 3);
root = tree.insert(root, 8);
root = tree.insert(root, 7);
root = tree.insert(root, 2);
root = tree.insert(root, 4);
System.out.println(root);
//结果>>>TreeNode [val=6, left=TreeNode [val=3, left=TreeNode [val=2, left=null, right=null], right=TreeNode [val=4, left=null, right=null]], right=TreeNode [val=8, left=TreeNode [val=7, left=null, right=null], right=null]]
二叉查找树的遍历
1.前序
1)递归写法:
/**
* 前序----根-左-右
*/
public void preOrder(TreeNode root) {
if (root == null) {
return;
}
System.out.println(root.val + " "); // 根
preOrder(root.left);// 左
preOrder(root.right);// 右
}
测试:
@Test
public void test() {
BST tree = new BST();
tree.add(6);
tree.add(3);
tree.add(8);
tree.add(7);
tree.add(2);
tree.add(4);
System.out.println("前序:");
tree.preOrder(tree.getRoot());
2)非递归写法:
public class QianXudemo {
/**
* 迭代法--前序
*/
public List<Integer> qianXu(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>(); // 构建辅助栈
if (root == null) { // 空树
return list;
}
stack.push(root); // 入栈操作
while (stack != null) { // 终止条件
TreeNode tmp = stack.pop(); // 弹出当前元素
list.add(tmp.val);
if (tmp.right != null) {
stack.push(tmp.right);
} else if (tmp.left != null) {
stack.push(tmp.left);
}
}
return list;
}
}
2.中序
1)递归写法:
/**
* 中序----左-根-右
*/
public void inOrder(TreeNode root) {
if (root == null) {
return;
}
inOrder(root.left);// 左
System.out.println(root.val + " "); // 根
inOrder(root.right);// 右
}
测试:
@Test
public void test() {
BST tree = new BST();
tree.add(6);
tree.add(3);
tree.add(8);
tree.add(7);
tree.add(2);
tree.add(4);
System.out.println("中序:");
tree.inOrder(tree.getRoot());
2)非递归写法:
public class ZhongXudemo {
/**
* 迭代法--中序
*/
public List<Integer> zhongXu(TreeNode root){
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>(); //构建辅助栈,利用其先入后出的特点
TreeNode tmp = root;
While(tmp!=null || !stack.isempty()){
while(tmp!=null) {
stack.push(tmp);
tmp = tmp.left; //遍历左子树
}
tmp = stack.pop(); //弹出栈
list.add(tmp.val); //存入数组中,加入当前节点
tmp = tmp.right; //遍历右子树
}
return list;
}
}
3.后序
1)递归写法:
/**
* 后序----左-右-根
*/
public void postOrder(TreeNode root) {
if (root == null) {
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.println(root.val + " "); // 根
}
测试:
@Test
public void test() {
BST tree = new BST();
tree.add(6);
tree.add(3);
tree.add(8);
tree.add(7);
tree.add(2);
tree.add(4);
System.out.println("后序:");
tree.postOrder(tree.getRoot());
2)非递归写法:
public class HouXuDemo {
public List<Integer> houXu(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode tmp = root;
while (tmp != null || !stack.isEmpty()) {
while (tmp != null) {
stack.push(tmp);
tmp = tmp.left; // 开始遍历左子树
}
TreeNode t = stack.peek(); // 获得当前的栈顶元素
if (t.right == null) { // 当前栈顶元素没有右节点
list.add(stack.pop().val); // 将其加入list数组中
} else {
// 将当前结点的右节点保存起来,并将其置为null
tmp = t.right;
t.right = null;
}
}
return list;
}
}
4.层级优先—广度优先
/**
* 层级优先---广度优先
*/
public void levelOrder(TreeNode root) {
if (root == null) {
return;
}
Queue<TreeNode> q = new LinkedList<>();
q.offer(root); // 将root存入队列中
while (!q.isEmpty()) { // 终止条件
TreeNode tmp = q.poll();// 弹出
System.out.print(tmp.val + " ");
if (tmp.left != null) {
q.offer(tmp.left);
}
if (tmp.right != null) {
q.offer(tmp.right);
}
}
}
测试:
@Test
public void test() {
BST tree = new BST();
tree.add(6);
tree.add(3);
tree.add(8);
tree.add(7);
tree.add(2);
tree.add(4);
System.out.println("层级优先:");
tree.levelOrder(tree.getRoot());
二叉查找树的删除
代码实例:
/**
* 二叉树删除
*
* @param root
* @param val
* @return
*/
public TreeNode delete(TreeNode root, int val) {
if (root.val == val) { // 找到要删除的数,要删除的数与root相等时
System.out.println("找到要删除节点:" + root);
if (root.left == null && root.right == null) { // 左右都无节点
return null;
} else if (root.left == null) { // 有右节点
return root.right;
} else if (root.right == null) { // 有左节点
return root.left;
} else if (root.left != null && root.right != null) { // 有左右两个节点
TreeNode min = minNode(root.right);
root.val = min.val;
root.right = delete(root.right, min.val);
}
} else if (val < root.val) { // 找到要删除的数,要删除的数小于root时---左子树
root.left = delete(root.left, val);
} else if (val > root.val) { // 找到要删除的数,要删除的数大于root时---右子树
root.right = delete(root.right, val);
}
return root;
}
public TreeNode minNode(TreeNode node) { // 找到最小节点
while (node.left != null) {
node = node.left;
}
return node;
}
测试:
@Test
public void test() {
BST tree = new BST();
tree.add(6);
tree.add(3);
tree.add(8);
tree.add(7);
tree.add(2);
tree.add(4);
System.out.println("删除:");
tree.delete(tree.getRoot(), 4);
System.out.println(tree);