由于上个文件字数到达2w以上,本软件加载比较麻烦,故而新建一个文件用来记录。
数据结构与算法
9 哈希表
一种数据结构
一般有hashMap,hashtable
哈希表,是一种数据结构,主要是key 与value的关系,了解hash表之前,我们需要了解的是哈希表,需要知道哈希函数,在jdk1.8之后,采用的红黑树进行一定的存储,其是根据关键码值而进行访问的数据结构,也就是说,其通过把关键码映射到表中的一个位置来访问记录,以加快查找的速度,这个映射函数我们称之为散列函数,存放记录的数组叫做散列表。
hashtable来存储雇员信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
| public class HashtableDemo {
public static void main(String[] args) { hashTable hashtab = new hashTable(8); Emp Emp1 = new Emp(10,"社会虎"); Emp Emp2 = new Emp(18,"废物刀"); Emp Emp3 = new Emp(26,"黑牛"); Emp Emp4 = new Emp(3,"白牛"); Emp Emp5 = new Emp(193,"小亮"); Emp Emp6 = new Emp(231,"唐老鸭"); Emp Emp7 = new Emp(12,"百特曼"); Emp Emp8 = new Emp(1,"独爱小尹"); Emp Emp9 = new Emp(123,"丽丽"); Emp Emp10 = new Emp(126,"带篮子"); Emp Emp11 = new Emp(29,"刘墉"); Emp Emp12 = new Emp(86,"丁真"); Emp Emp13 = new Emp(800,"王冰冰");
hashtab.add(Emp1); hashtab.add(Emp2); hashtab.add(Emp3); hashtab.add(Emp4); hashtab.add(Emp5); hashtab.add(Emp6); hashtab.add(Emp7); hashtab.add(Emp8); hashtab.add(Emp9); hashtab.add(Emp10); hashtab.add(Emp11); hashtab.add(Emp12); hashtab.add(Emp13); hashtab.list(); } }
class hashTable{ private int size; private EmpLinkedList[] empLinkedLists; public hashTable(int size) { this.size = size; empLinkedLists = new EmpLinkedList[size]; for(int i = 0 ; i < size; i++) { empLinkedLists[i] = new EmpLinkedList(); } } public int hash(int id) { return id % size; } public void add(Emp emp){ int num = hash(emp.id); empLinkedLists[num].add(emp); } public void list() { for(int i = 0 ; i < size ; i ++ ) { System.out.println("第"+i+"个链表状况"); empLinkedLists[i].list(); } } }
class Emp{ public int id; public String name; public Emp next; public Emp() { super(); } public Emp(int id, String name) { super(); this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Emp getNext() { return next; } public void setNext(Emp next) { this.next = next; } }
class EmpLinkedList{ private Emp head; public void add(Emp emp) { if(head == null ) { head = emp; return ; } Emp curEmp = head; while(true) { if(curEmp.next == null) { break; } curEmp = curEmp.next; } curEmp.next = emp; } public void list() { if(head == null) { System.out.println("当前链表为空"); return ; } System.out.println("当前链表的信息为:"); Emp cuEmp = head ; int count = 0; while(true) { System.out.printf("id = %d name = %s\n",cuEmp.id,cuEmp.name); count ++; if(cuEmp.next == null ) { System.out.println("共计有"+ count+ "个"); break; } cuEmp = cuEmp.next; } } }
|
10.数据结构的存储方式
10.1二叉树
数组的存储方式的分析
优点:通过下标方式访问元素,速度快。对于有序数组,还可以使用二分查找提高检索速度。
缺点:如果要检索具体某个值,或者插入值(按照一定顺序)会整体移动,效率较低。
链式存储方式的分析
优点:在一定程度上对数组的存储方式有优化(比如:插入一个数值节点,只需要将插入节点,链接到链表中即可,删除效率也很好)
缺点:在进行检索时,效率仍然比较低,比如(检索某个值,需要从头结点开始遍历)
树存储方式的分析
优点:可以提高数据存储,读取的效率,比如利用二叉排序树,既可以保证数据的检索速度,同时也可以保证数据的插入,删除,修改的速度。
缺点:顺序存储可能会浪费空间(在非完全二叉树的时候,但是读取某个特定的节点的时候效率比较高O(0));链式存储相对于二叉树,浪费空间较少,但是读取某个结点时效率偏低O(nlogn)。
10.2 二叉树的概率和常用术语
满二叉树:在一个二叉树中,如果所有分支节点都有左孩子节点和右孩子节点,并且叶节点都集中在二叉树中的最下一层,这样的二叉树被称为满二叉树。
完全二叉树:若二叉树中最多只有最下面两层的结点的度数可以小于2,并且最下面一层的叶子节点,都依次排列在该层最左边的位置上,这样的二叉树称为完全二叉树。
遍历和节点删除
二叉树是一种非常重要的数据结构,非常多的数据结构都是基于二叉树的基础演变而来的。对于二叉树有深度遍历和广度遍历,深度遍历有前序、中序以及后序三种遍历方法,广度遍历即我们寻常所说的层次遍历。由于树的定义本身就是递归定义,因此采用递归的方法实现树的三种遍历。
- 前序遍历:根结点 —>左子树—>右子树;
- 中序遍历:左子树 —>根结点—>右子树;
- 后续遍历:左子树 —>右子树—>根结点;
- 层次遍历:仅仅需按成次遍历即可;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
| public class BinaryTreeDemo { public static void main(String[] args) { BinaryTree binaryTree = new BinaryTree(); HeroNode root = new HeroNode(1, "宋江"); HeroNode node2 = new HeroNode(2, "卢俊义"); HeroNode node3 = new HeroNode(3, "吴用"); HeroNode node4 = new HeroNode(4, "公孙胜"); HeroNode node5 = new HeroNode(5, "关胜"); root.setLeft(node2); root.setRight(node3); node3.setLeft(node4); node3.setRight(node5); binaryTree.setRoot(root); System.out.println("前序遍历"); binaryTree.preOrder(); System.out.println("中序遍历"); binaryTree.midOrder(); System.out.println("后序遍历"); binaryTree.postOrder(); binaryTree.delNode(3); System.out.println("删除结点3,前序遍历"); binaryTree.preOrder(); } }
class BinaryTree { private HeroNode root;
public HeroNode getRoot() { return root; }
public void setRoot(HeroNode root) { this.root = root; } public void preOrder() { if(this.root != null) { this.root.preOrder(); }else { System.out.println("二叉树为空,不能遍历"); } } public void midOrder() { if(this.root != null) { this.root.midOrder(); }else { System.out.println("二叉树为空,无法遍历"); } } public void postOrder() { if(this.root != null) { this.root.postOrder(); }else { System.out.println("二叉树为空,无法遍历"); } }
public void delNode(int no) { if(root != null) { if(root.getNo() == no) { root = null; } else { root.delNode(no); } }else{ System.out.println("空树,不能删除~"); } } }
class HeroNode { private int no; private String name; private HeroNode left; private HeroNode right; public HeroNode(int no, String name) { this.no = no; this.name = name; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } public String getName() { return name; } public void setName(String name) { this.name = name; } public HeroNode getLeft() { return left; } public void setLeft(HeroNode left) { this.left = left; } public HeroNode getRight() { return right; } public void setRight(HeroNode right) { this.right = right; } @Override public String toString() { return "HeroNode [no=" + no + ", name=" + name + "]"; }
public void preOrder() { System.out.println(this); if(this.left != null) { this.left.preOrder(); } if(this.right != null) { this.right.preOrder(); } }
public void midOrder() { if(this.left != null) { this.left.midOrder(); } System.out.println(this); if(this.right != null) { this.right.midOrder(); } }
public void postOrder() { if(this.left != null) { this.left.postOrder(); } if(this.right != null) { this.right.postOrder(); } System.out.println(this); }
public void delNode(int no) {
if(this.left != null && this.left.no == no) { this.left = null; return; }
if(this.right != null && this.right.no == no) { this.right = null; return; }
if(this.left != null) { this.left.delNode(no); }
if(this.right != null) { this.right.delNode(no); } } }
|
10.3链式存储
查找节点:先对树进行一次遍历,然后找出要找的那个数;因为有三种排序方法,所以查找节点也分为先序查找,中序查找,后序查找;
删除节点:由于链式存储,不能找到要删的数直接删除,需要找到他的父节点,然后将指向该数设置为null;所以需要一个变量来指向父节点,找到数后,再断开连接。
树:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class BinaryTree {
TreeNode root;
public void setRoot(TreeNode root) { this.root = root; }
public TreeNode getRoot() { return root; }
public void frontShow() { if (root != null) { root.frontShow(); } }
public void middleShow() { if (root != null) { root.middleShow(); } }
public void afterShow() { if (root != null) { root.afterShow(); } }
public TreeNode frontSearch(int i) { return root.frontSearch(i); }
public void delete(int i) { if (root.value == i) { root = null; } else { root.delete(i); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
| public class TreeNode { int value; TreeNode leftNode; TreeNode rightNode;
public TreeNode(int value) { this.value = value; }
public void setLeftNode(TreeNode leftNode) { this.leftNode = leftNode; }
public void setRightNode(TreeNode rightNode) { this.rightNode = rightNode; }
public void frontShow() { System.out.print(value + " "); if (leftNode != null) { leftNode.frontShow(); } if (rightNode != null) { rightNode.frontShow(); } }
public void middleShow() { if (leftNode != null) { leftNode.middleShow(); } System.out.print(value + " "); if (rightNode != null) { rightNode.middleShow(); } }
public void afterShow() { if (leftNode != null) { leftNode.afterShow(); } if (rightNode != null) { rightNode.afterShow(); } System.out.print(value + " "); }
public TreeNode frontSearch(int i) { TreeNode target = null; if (this.value == i) { return this; } else { if (leftNode != null) { target = leftNode.frontSearch(i); } if (target != null) { return target; } if (rightNode != null) { target = rightNode.frontSearch(i); } } return target; }
public void delete(int i) { TreeNode parent = this; if (parent.leftNode != null && parent.leftNode.value == i) { parent.leftNode = null; return; } if (parent.rightNode != null && parent.rightNode.value == i) { parent.rightNode = null; return; } parent = leftNode; if (parent != null) { parent.delete(i); } parent = rightNode; if (parent != null) { parent.delete(i); }
} }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class Demo { public static void main(String[] args) { BinaryTree binaryTree = new BinaryTree(); TreeNode root = new TreeNode(1); binaryTree.setRoot(root); TreeNode rootLeft = new TreeNode(2); TreeNode rootRight = new TreeNode(3); root.setLeftNode(rootLeft); root.setRightNode(rootRight); rootLeft.setLeftNode(new TreeNode(4)); rootLeft.setRightNode(new TreeNode(5)); rootRight.setLeftNode(new TreeNode(6)); rootRight.setRightNode(new TreeNode(7));
binaryTree.frontShow(); System.out.println(); binaryTree.middleShow(); System.out.println(); binaryTree.afterShow(); System.out.println();
TreeNode result = binaryTree.frontSearch(5); System.out.println(result);
binaryTree.delete(2); binaryTree.frontShow(); } }
|
10.4顺序存储的二叉树
概述:顺序存储使用数组的形式实现;由于非完全二叉树会导致数组中出现空缺,有的位置不能填上数字,所以顺序存储二叉树通常情况下只考虑完全二叉树
原理: 顺序存储在数组中是按照第一层第二层一次往下存储的,遍历方式也有先序遍历、中序遍历、后续遍历
性质:
- 第n个元素的左子节点是:2*n+1;
- 第n个元素的右子节点是:2*n+2;
- 第n个元素的父节点是:(n-1)/2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public class ArrayBinaryTree {
public static void main(String[] args) { int[] data = {1,2,3,4,5,6,7}; ArrayBinaryTree tree = new ArrayBinaryTree(data); tree.frontShow(); }
int[] data;
public ArrayBinaryTree(int[] data) { this.data = data; }
public void frontShow() { frontShow(0); }
public void frontShow(int index) { if (data == null || data.length == 0) { return; } System.out.print(data[index] + " "); if (2 * index + 1 < data.length) { frontShow(2 * index + 1); } if (2 * index + 2 < data.length) { frontShow(2 * index + 2); } } }
|
10.5线索二叉树
为什么使用线索二叉树?
当用二叉链表作为二叉树的存储结构时,可以很方便的找到某个结点的左右孩子;但一般情况下,无法直接找到该结点在某种遍历序列中的前驱和后继结点
原理:n个结点的二叉链表中含有n+1(2n-(n-1)=n+1个空指针域。利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前驱和后继结点的指针。
例如:某个结点的左孩子为空,则将空的左孩子指针域改为指向其前驱;如果某个结点的右孩子为空,则将空的右孩子指针域改为指向其后继(这种附加的指针称为”线索”)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| public class ThreadedBinaryTree {
ThreadedNode root; ThreadedNode pre = null; public void setRoot(ThreadedNode root) { this.root = root; }
public void threadNodes() { threadNodes(root); }
public void threadNodes(ThreadedNode node) { if (node == null) { return; } threadNodes(node.leftNode);
if (node.leftNode == null) { node.leftNode = pre; node.leftType = 1; } if (pre != null && pre.rightNode == null) { pre.rightNode = node; pre.rightType = 1; }
pre = node;
threadNodes(node.rightNode); }
public void threadIterate() { ThreadedNode node = root; while (node != null) { while (node.leftType == 0) { node = node.leftNode; } System.out.print(node.value + " "); while (node.rightType == 1) { node = node.rightNode; System.out.print(node.value + " "); } node = node.rightNode;
} }
public ThreadedNode getRoot() { return root; }
public void frontShow() { if (root != null) { root.frontShow(); } }
public void middleShow() { if (root != null) { root.middleShow(); } }
public void afterShow() { if (root != null) { root.afterShow(); } }
public ThreadedNode frontSearch(int i) { return root.frontSearch(i); }
public void delete(int i) { if (root.value == i) { root = null; } else { root.delete(i); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| public class ThreadedNode { int value; ThreadedNode leftNode; ThreadedNode rightNode; int leftType; int rightType;
public ThreadedNode(int value) { this.value = value; }
public void setLeftNode(ThreadedNode leftNode) { this.leftNode = leftNode; }
public void setRightNode(ThreadedNode rightNode) { this.rightNode = rightNode; }
public void frontShow() { System.out.print(value + " "); if (leftNode != null) { leftNode.frontShow(); } if (rightNode != null) { rightNode.frontShow(); } }
public void middleShow() { if (leftNode != null) { leftNode.middleShow(); } System.out.print(value + " "); if (rightNode != null) { rightNode.middleShow(); } }
public void afterShow() { if (leftNode != null) { leftNode.afterShow(); } if (rightNode != null) { rightNode.afterShow(); } System.out.print(value + " "); }
public ThreadedNode frontSearch(int i) { ThreadedNode target = null; if (this.value == i) { return this; } else { if (leftNode != null) { target = leftNode.frontSearch(i); } if (target != null) { return target; } if (rightNode != null) { target = rightNode.frontSearch(i); } } return target; }
public void delete(int i) { ThreadedNode parent = this; if (parent.leftNode != null && parent.leftNode.value == i) { parent.leftNode = null; return; } if (parent.rightNode != null && parent.rightNode.value == i) { parent.rightNode = null; return; } parent = leftNode; if (parent != null) { parent.delete(i); } parent = rightNode; if (parent != null) { parent.delete(i); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class Demo { public static void main(String[] args) { ThreadedBinaryTree binaryTree = new ThreadedBinaryTree(); ThreadedNode root = new ThreadedNode(1); binaryTree.setRoot(root); ThreadedNode rootLeft = new ThreadedNode(2); ThreadedNode rootRight = new ThreadedNode(3); root.setLeftNode(rootLeft); root.setRightNode(rootRight); rootLeft.setLeftNode(new ThreadedNode(4)); ThreadedNode fiveNode = new ThreadedNode(5); rootLeft.setRightNode(fiveNode); rootRight.setLeftNode(new ThreadedNode(6)); rootRight.setRightNode(new ThreadedNode(7));
binaryTree.middleShow(); System.out.println(); binaryTree.threadNodes();
binaryTree.threadIterate(); } }
|
10.6二叉排序树
概述:二叉排序树(Binary Sort Tree)也叫二叉查找树或者是一颗空树,对于二叉树中的任何一个非叶子节点,要求左子节点比当前节点值小,右子节点比当前节点值大
特点:
- 查找性能与插入删除性能都适中还不错
- 中序遍历的结果刚好是从大到小
创建二叉排序树原理:其实就是不断地插入节点,然后进行比较。
删除节点
- 删除叶子节点,只需要找到父节点,将父节点与他的连接断开即可
- 删除有一个子节点的就需要将他的子节点换到他现在的位置
- 删除有两个子节点的节点,需要使用他的前驱节点或者后继节点进行替换,就是左子树最右下方的数(最大的那个)或右子树最左边的树(最小的数);即离节点值最接近的值;(还要注解要去判断这个值有没有右节点,有就要将右节点移上来)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| public class BinarySortTree { Node root;
public void add(Node node) { if (root == null) { root = node; } else { root.add(node); } }
public void middleShow() { if (root != null) { root.middleShow(root); } }
public Node search(int value) { if (root == null) { return null; } return root.search(value); }
public Node searchParent(int value) { if (root == null) { return null; } return root.searchParent(value); }
public void delete(int value) { if (root == null) { return; } else { Node target = search(value); if (target == null) { return; } Node parent = searchParent(value); if (target.left == null && target.left == null) { if (parent.left.value == value) { parent.left = null; } else { parent.right = null; } } else if (target.left != null && target.right != null) { int min = deletMin(target.right); target.value = min; } else { if (target.left != null) { if (parent.left.value == value) { parent.left = target.left; } else { parent.right = target.left; }
} else { if (parent.left.value == value) { parent.left = target.right; } else { parent.right = target.right; } } } } }
private int deletMin(Node node) { Node target = node; while (target.left != null) { target = target.left; } delete(target.value); return target.value; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| public class Node { int value; Node left; Node right;
public Node(int value) { this.value = value; }
public void add(Node node) { if (node == null) { return; } if (node.value < this.value) { if (this.left == null) { this.left = node;
} else { this.left.add(node); }
} else { if (this.right == null) { this.right = node; } else { this.right.add(node); } } }
public void middleShow(Node node) { if (node == null) { return; } middleShow(node.left); System.out.print(node.value + " "); middleShow(node.right); }
public Node search(int value) { if (this.value == value) { return this; } else if (value < this.value) { if (left == null) { return null; } return left.search(value); } else { if (right == null) { return null; } return right.search(value); } }
public Node searchParent(int value) { if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)) { return this; } else { if (this.value > value && this.left != null) { return this.left.searchParent(value); } else if (this.value < value && this.right != null) { return this.right.searchParent(value); } return null; } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public class Demo { public static void main(String[] args) { int[] arr = {8, 3, 10, 1, 6, 14, 4, 7, 13}; BinarySortTree bst = new BinarySortTree();
for (int i : arr) { bst.add(new Node(i)); }
bst.middleShow(); System.out.println();
Node node = bst.search(10); System.out.println(node.value);
Node node2 = bst.search(20); System.out.println(node2);
Node node3 = bst.searchParent(1); Node node4 = bst.searchParent(14); System.out.println(node3.value); System.out.println(node4.value);
bst.delete(3); bst.middleShow(); } }
|
10.7平衡二叉树
平衡二叉树(Balanced Binary Tree)又被称为AVL树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)
。但是频繁旋转会使插入和删除牺牲掉O(logN)
左右的时间,不过相对二叉查找树来说,时间上稳定了很多。
平衡因子 BF
- 定义:左子树和右子树高度差
- 计算:
左子树高度 - 右子树高度的值
- 别名:简称 BF(Balance Factor)
- 一般来说 BF 的绝对值大于 1,,平衡树二叉树就失衡,需要旋转纠正
最小不平衡子树
- 距离插入节点最近的,并且 BF 的绝对值大于 1 的节点为根节点的子树。
- 旋转纠正只需要纠正最小不平衡子树即可
旋转方式
2 种旋转方式:
左旋 :
- 旧根节点为新根节点的左子树
- 新根节点的左子树(如果存在)为旧根节点的右子树
右旋:
- 旧根节点为新根节点的右子树
- 新根节点的右子树(如果存在)为旧根节点的左子树
4 种旋转纠正类型:
- 左左型:插入左孩子的左子树,右旋
- 右右型:插入右孩子的右子树,左旋
- 左右型:插入左孩子的右子树,先左旋,再右旋
- 右左型:插入右孩子的左子树,先右旋,再左旋
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
| public class Node { int value; Node left; Node right;
public Node(int value) { this.value = value; }
public int height() { return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1; }
public int leftHeight() { if (left == null) { return 0; } return left.height(); }
public int rightHeight() { if (right == null) { return 0; } return right.height(); }
public void add(Node node) { if (node == null) { return; } if (node.value < this.value) { if (this.left == null) { this.left = node;
} else { this.left.add(node); }
} else { if (this.right == null) { this.right = node; } else { this.right.add(node); } } if (leftHeight() - rightHeight() >= 2) { if (left != null && left.leftHeight() < left.rightHeight()) { left.leftRotate(); rightRotate(); } else { rightRotate(); } } if (leftHeight() - rightHeight() <= -2) { if (right != null && right.rightHeight() < right.leftHeight()) { right.rightRotate(); leftRotate(); } else { leftRotate(); } } }
private void rightRotate() { Node newRight = new Node(value); newRight.right = right; newRight.left = left.right; value = left.value; left = left.left; right = newRight; }
private void leftRotate() { Node newLeft = new Node(value); newLeft.left = left; newLeft.right = right.left; value = right.value; right = right.right; left = newLeft; }
public void middleShow(Node node) { if (node == null) { return; } middleShow(node.left); System.out.print(node.value + " "); middleShow(node.right); }
public Node search(int value) { if (this.value == value) { return this; } else if (value < this.value) { if (left == null) { return null; } return left.search(value); } else { if (right == null) { return null; } return right.search(value); } }
public Node searchParent(int value) { if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)) { return this; } else { if (this.value > value && this.left != null) { return this.left.searchParent(value); } else if (this.value < value && this.right != null) { return this.right.searchParent(value); } return null; } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Demo { public static void main(String[] args) { int[] arr = {1,2,3,4,5,6}; BinarySortTree bst = new BinarySortTree(); for (int i : arr) { bst.add(new Node(i)); } System.out.println(bst.root.height()); System.out.println(bst.root.value); System.out.println(bst.root.left.value); System.out.println(bst.root.right.value); } }
|