内容概要:
线性表和链表 链表与单链表介绍
单链表的应用 基本介绍
代码实现 单链表的 创建、遍历、插入以及顺序插入 代码如下:
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 public class SingleLinkedListTest { public static void main (String[] args) { HeroNode heroNode1 = new HeroNode(1 , "松江" , "及时雨" ); HeroNode heroNode2 = new HeroNode(2 , "卢俊义" , "玉麒麟" ); HeroNode heroNode3 = new HeroNode(3 , "吴用" , "智多星" ); HeroNode heroNode4 = new HeroNode(4 , "林冲" , "豹子头" ); SingleLinkedList singleLinkedList = new SingleLinkedList(); singleLinkedList.addByOrder(heroNode1); singleLinkedList.addByOrder(heroNode4); singleLinkedList.addByOrder(heroNode3); singleLinkedList.addByOrder(heroNode2); singleLinkedList.addByOrder(heroNode2); singleLinkedList.showList(); } } class SingleLinkedList { private HeroNode head = new HeroNode(0 , "" , "" ); public HeroNode getHead () { return head; } public void add (HeroNode heroNode) { HeroNode temp = head; while (true ) { if (temp.next == null ) { break ; } temp = temp.next; } temp.next = heroNode; } public void addByOrder (HeroNode heroNode) { HeroNode temp = head; boolean flag = false ; while (true ){ if (temp.next == null ){ break ; } if (temp.next.no > heroNode.no){ break ; } else if (temp.next.no == heroNode.no){ flag = true ; break ; } temp = temp.next; } if (flag){ System.out.printf("待插入的英雄编号 %d 已经存在了,不能加入!" , heroNode.no); } else { heroNode.next = temp.next; temp.next = heroNode; } } public void showList () { if (head.next == null ) { System.out.println("链表为空" ); return ; } HeroNode temp = head.next; while (true ) { if (temp == null ) { break ; } System.out.println(temp); temp = temp.next; } } } class HeroNode { public int no; public String name; public String nickname; public HeroNode next; public HeroNode (int no, String name, String nickname) { this .no = no; this .name = name; this .nickname = nickname; } @Override public String toString () { return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", nickname='" + nickname + '\'' + '}' ; } }
单链表的节点信息的 修改操作 ,代码如下:
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 HeroNode heroNode = new HeroNode(2 ,"小卢" ,"玉麒麟~~~" ); singleLinkedList.update(heroNode); singleLinkedList.showList(); public void update (HeroNode heroNode) { if (head.next == null ) { System.out.println("链表为空!!!" ); return ; } HeroNode temp = head.next; boolean flag = false ; while (true ) { if (temp.next == null ) { break ; } if (temp.no == heroNode.no) { flag = true ; break ; } temp = temp.next; } if (flag) { temp.name = heroNode.name; temp.nickname = heroNode.nickname; } else { System.out.printf("没有找到编号为 %d 的节点,不能修改!!!" , heroNode.no); } }
单链表的节点信息的 删除操作 ,代码如下:
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 singleLinkedList.delete(1 ); singleLinkedList.delete(5 ); System.out.println("删除后链表的情况~~~~~" ); singleLinkedList.showList(); public void delete (int no) { HeroNode temp = head; boolean flag = false ; while (true ) { if (temp.next == null ) { break ; } if (temp.next.no == no) { flag = true ; break ; } temp = temp.next; } if (flag) { temp.next = temp.next.next; } else { System.out.printf("要删除的 %d 节点不存在\n" , no); } }
单链表面试题
解决 第一个 题目:求单链表中有效节点的个数 ,代码如下:
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 HeroNode head = singleLinkedList.getHead(); int length = SingleLinkedList.getLength(head);System.out.println("有效节点个数为:" + length); public static int getLength (HeroNode heroNode) { if (heroNode.next == null ) { return 0 ; } int length = 0 ; HeroNode cur = heroNode.next; while (cur != null ) { length++; cur = cur.next; } return length; }
解决 第二个 题目:查找单链表中的倒数第 k 个节点【新浪面试题】 ,代码如下:
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 HeroNode res1 = SingleLinkedList.findNode(singleLinkedList.getHead(), 2 ); System.out.println("res = " + res1); HeroNode res2 = SingleLinkedList.findNode(singleLinkedList.getHead(), 5 ); System.out.println("res = " + res2); public static HeroNode findNode (HeroNode head, int index) { if (head.next == null ) { return null ; } int length = getLength(head); if (index <= 0 || index > length) { return null ; } HeroNode cur = head.next; for (int i = 0 ; i < (length - index); i++) { cur = cur.next; } return cur; }
解决 第三个 题目:单链表的反转【腾讯面试题】 ,代码如下:
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 System.out.println("原来链表的情况~~~" ); singleLinkedList.showList(); System.out.println("反转后链表的情况~~~" ); SingleLinkedList.reverseList(head); singleLinkedList.showList(); public static void reverseList (HeroNode head) { if (head.next == null || head.next.next == null ) { return ; } HeroNode cur = head.next; HeroNode next = null ; HeroNode reverseHead = new HeroNode(0 , "" , "" ); while (cur != null ) { next = cur.next; cur.next = reverseHead.next; reverseHead.next = cur; cur = next; } head.next = reverseHead.next; }
解决 第四个 题目:从尾到头打印单链表【百度面试题:要求方式1:反向遍历。要求方式2:Stack 栈】 ,代码如下:
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 SingleLinkedList.revesrePrint(head); public static void revesrePrint (HeroNode head) { if (head.next == null ){ return ; } Stack<HeroNode> stack = new Stack<>(); HeroNode cur = head.next; while (cur != null ){ stack.push(cur); cur = cur.next; } while (stack.size() > 0 ){ System.out.println(stack.pop()); } }
双向链表 基本介绍 学完单链表发现,单链表只能从头结点开始访问链表中的数据元素,如果需要逆序访问单链表中的数据元素将极其低效。因而出现了 双链表结构 。双链表 是链表的一种,由节点组成,每个数据结点中都有两个指针,分别指向 直接后继 和 直接前驱 。双链表结构如下图:
应用实现 使用 双链表 对上述单链表的功能进行再次实现,代码如下:
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 public class DoubleLinkedListTest { public static void main (String[] args) { System.out.println("双向链表测试~~~" ); HeroDoubleNode heroNode1 = new HeroDoubleNode(1 , "松江" , "及时雨" ); HeroDoubleNode heroNode2 = new HeroDoubleNode(2 , "卢俊义" , "玉麒麟" ); HeroDoubleNode heroNode3 = new HeroDoubleNode(3 , "吴用" , "智多星" ); HeroDoubleNode heroNode4 = new HeroDoubleNode(4 , "林冲" , "豹子头" ); DoubleLinkedList doubleLinkedList = new DoubleLinkedList(); doubleLinkedList.add(heroNode1); doubleLinkedList.add(heroNode2); doubleLinkedList.add(heroNode3); doubleLinkedList.add(heroNode4); doubleLinkedList.showList(); HeroDoubleNode newNode = new HeroDoubleNode(4 , "Jack" , "Jacky" ); doubleLinkedList.update(newNode); System.out.println("修改后双向链表~~~" ); doubleLinkedList.showList(); doubleLinkedList.delete(3 ); System.out.println("删除后双向链表~~~" ); doubleLinkedList.showList(); } } class DoubleLinkedList { private HeroDoubleNode head = new HeroDoubleNode(0 , "" , "" ); public HeroDoubleNode getHead () { return head; } public void showList () { if (head.next == null ) { System.out.println("链表为空" ); return ; } HeroDoubleNode temp = head.next; while (true ) { if (temp == null ) { break ; } System.out.println(temp); temp = temp.next; } } public void add (HeroDoubleNode heroNode) { HeroDoubleNode temp = head; while (true ) { if (temp.next == null ) { break ; } temp = temp.next; } temp.next = heroNode; heroNode.pre = temp; } public void update (HeroDoubleNode heroNode) { if (head.next == null ) { System.out.println("链表为空!!!" ); return ; } HeroDoubleNode temp = head.next; boolean flag = false ; while (true ) { if (temp == null ) { break ; } if (temp.no == heroNode.no) { flag = true ; break ; } temp = temp.next; } if (flag) { temp.name = heroNode.name; temp.nickname = heroNode.nickname; } else { System.out.printf("没有找到编号为 %d 的节点,不能修改!!!" , heroNode.no); } } public void delete (int no) { if (head.next == null ){ System.out.println("链表为空,无法删除!!!" ); return ; } HeroDoubleNode temp = head.next; boolean flag = false ; while (true ) { if (temp == null ) { break ; } if (temp.no == no) { flag = true ; break ; } temp = temp.next; } if (flag) { temp.pre.next = temp.next; if (temp.next != null ){ temp.next.pre = temp.pre; } } else { System.out.printf("要删除的 %d 节点不存在\n" , no); } } } class HeroDoubleNode { public int no; public String name; public String nickname; public HeroDoubleNode next; public HeroDoubleNode pre; public HeroDoubleNode (int no, String name, String nickname) { this .no = no; this .name = name; this .nickname = nickname; } @Override public String toString () { return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", nickname='" + nickname + '\'' + '}' ; } }
环形链表 基本介绍 环形链表 ,类似于单链表,也是一种链式存储结构,环形链表由单链表演化过来。单链表的最后一个结点的链域指向 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 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 public class Josephu { public static void main (String[] args) { CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList(); circleSingleLinkedList.addBoy(5 ); circleSingleLinkedList.showNode(); circleSingleLinkedList.countBoyNode(1 , 2 , 5 ); } } class CircleSingleLinkedList { private BoyNode first = null ; public void addBoy (int num) { if (num < 1 ) { System.out.println("参数小于 1 ,不正确!!!" ); return ; } BoyNode curNode = null ; for (int i = 1 ; i <= num; i++) { BoyNode boyNode = new BoyNode(i); if (i == 1 ) { first = boyNode; first.setNext(first); curNode = first; } else { curNode.setNext(boyNode); boyNode.setNext(first); curNode = boyNode; } } } public void showNode () { if (first == null ) { System.out.println("链表为空,没有节点~~~" ); } BoyNode temp = first; while (true ) { System.out.printf("节点的编号 %d \n" , temp.getNo()); if (temp.getNext() == first) { break ; } temp = temp.getNext(); } } public void countBoyNode (int startsNo, int countNum, int nums) { if (first == null || startsNo < 1 || startsNo > nums) { System.out.println("参数输入有误,请重新输入!!!" ); return ; } BoyNode helper = first; while (true ) { if (helper.getNext() == first) { break ; } helper = helper.getNext(); } for (int i = 0 ; i < (startsNo - 1 ); i++) { first = first.getNext(); helper = helper.getNext(); } while (true ) { if (helper == first) { break ; } for (int i = 0 ; i < (countNum - 1 ); i++) { first = first.getNext(); helper = helper.getNext(); } System.out.printf("%d 节点出圈\n" , first.getNo()); first = first.getNext(); helper.setNext(first); } System.out.printf("最后留在圈中的节点是 %d \n" , first.getNo()); } } class BoyNode { private int no; private BoyNode next; public int getNo () { return no; } public void setNo (int no) { this .no = no; } public BoyNode getNext () { return next; } public void setNext (BoyNode next) { this .next = next; } public BoyNode (int no) { this .no = no; } }
栈和队列 栈的知识 认识栈
数组模拟栈 数组模拟栈的 思路分析 如下图:
数组模拟栈的 代码实现 如下:
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 public class ArrayStackTest { public static void main (String[] args) { ArrayStack stack = new ArrayStack(4 ); String key; boolean loop = true ; Scanner scanner = new Scanner(System.in); while (loop) { System.out.println("show: 显示栈" ); System.out.println("push: 压栈" ); System.out.println("pop: 出栈" ); System.out.println("exit: 退出程序" ); System.out.println("请输入相关操作:" ); key = scanner.next(); switch (key) { case "show" : stack.showStack(); break ; case "push" : System.out.println("请输入一个数:" ); int value = scanner.nextInt(); stack.push(value); break ; case "pop" : try { int res = stack.pop(); System.out.printf("出栈的数据是 %d \n" ,res); } catch (Exception e){ System.out.println(e.getMessage()); } break ; case "exit" : scanner.close(); loop = false ; break ; default : break ; } } System.out.println("程序退出了!!!" ); } } class ArrayStack { private int maxSize; private int [] stack; private int top = -1 ; public ArrayStack (int maxSize) { this .maxSize = maxSize; stack = new int [maxSize]; } public boolean isFull () { return top == maxSize - 1 ; } public boolean isEmpty () { return top == -1 ; } public void push (int value) { if (isFull()) { System.out.println("栈满!!!" ); return ; } top++; stack[top] = value; } public int pop () { if (isEmpty()) { throw new RuntimeException("栈空,没有数据!!!" ); } int value = stack[top]; top--; return value; } public void showStack () { if (isEmpty()) { System.out.println("栈空,没有数据!!!" ); return ; } for (int i = top; i >= 0 ; i--) { System.out.printf("stack[%d] = %d\n" , i, stack[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 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 public class Calculator { public static void main (String[] args) { String expression = "30+50*6-2" ; ArrayStack numStack = new ArrayStack(10 ); ArrayStack operStack = new ArrayStack(10 ); int index = 0 ; int num1; int num2; int oper; int res = 0 ; char ch; String keepNum = "" ; while (true ) { ch = expression.substring(index, index + 1 ).charAt(0 ); if (operStack.isOper(ch)) { if (!operStack.isEmpty()) { if (operStack.priority(ch) <= operStack.priority(operStack.peek())) { num1 = numStack.pop(); num2 = numStack.pop(); oper = operStack.pop(); res = numStack.cal(num1, num2, oper); numStack.push(res); operStack.push(ch); } else { operStack.push(ch); } } else { operStack.push(ch); } } else { keepNum += ch; if (index == expression.length() - 1 ) { numStack.push(Integer.parseInt(keepNum)); } else { if (operStack.isOper(expression.substring(index + 1 , index + 2 ).charAt(0 ))) { numStack.push(Integer.parseInt(keepNum)); keepNum = "" ; } } } index++; if (index >= expression.length()) { break ; } } while (true ) { if (operStack.isEmpty()) { break ; } else { num1 = numStack.pop(); num2 = numStack.pop(); oper = operStack.pop(); res = numStack.cal(num1, num2, oper); numStack.push(res); } } System.out.println("表达式最终结果:" + res); } } class ArrayStack { private int maxSize; private int [] stack; private int top = -1 ; public ArrayStack (int maxSize) { this .maxSize = maxSize; stack = new int [maxSize]; } public boolean isFull () { return top == maxSize - 1 ; } public boolean isEmpty () { return top == -1 ; } public void push (int value) { if (isFull()) { System.out.println("栈满!!!" ); return ; } top++; stack[top] = value; } public int pop () { if (isEmpty()) { throw new RuntimeException("栈空,没有数据!!!" ); } int value = stack[top]; top--; return value; } public void showStack () { if (isEmpty()) { System.out.println("栈空,没有数据!!!" ); return ; } for (int i = top; i >= 0 ; i--) { System.out.printf("stack[%d] = %d\n" , i, stack[i]); } } public int priority (int oper) { if (oper == '*' || oper == '/' ) { return 1 ; } else if (oper == '+' || oper == '-' ) { return 0 ; } else { return -1 ; } } public boolean isOper (char val) { return val == '+' || val == '-' || val == '*' || val == '/' ; } public int cal (int num1, int num2, int oper) { int res = 0 ; switch (oper) { case '+' : res = num1 + num2; break ; case '-' : res = num2 - num1; break ; case '*' : res = num2 * num1; break ; case '/' : res = num2 / num1; break ; default : break ; } return res; } public int peek () { return stack[top]; } }
前、中、后缀表达式 前缀表达式 基本介绍如下:
中缀表达式 基本介绍如下:
后缀表达式 基本介绍如下:
逆波兰计算器
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 public class PolandNotation { public static void main (String[] args) { String suffixExpression = "3 4 + 5 * 6 -" ; List<String> list = getListstring(suffixExpression); System.out.println(list); int res = calculate(list); System.out.println("逆波兰表达式最终结果:" + res); System.out.println(); String suffixExp = "4 5 * 8 - 60 + 8 2 / +" ; List<String> stringList = getListstring(suffixExp); System.out.println(stringList); int calculate = calculate(stringList); System.out.println("逆波兰表达式最终结果:" + calculate); } public static List<String> getListstring (String suffixExpression) { String[] strings = suffixExpression.split(" " ); List<String> list = new ArrayList<>(); for (String string : strings) { list.add(string); } return list; } public static int calculate (List<String> ls) { Stack<String> strings = new Stack<>(); for (String item : ls) { if (item.matches("\\d+" )) { strings.push(item); } else { int num2 = Integer.parseInt(strings.pop()); int num1 = Integer.parseInt(strings.pop()); int res = 0 ; if (item.equals("+" )) { res = num1 + num2; } else if (item.equals("-" )) { res = num1 - num2; } else if (item.equals("*" )) { res = num1 * num2; } else if (item.equals("/" )) { res = num1 / num2; } else { throw new RuntimeException("运算符有误!!!" ); } strings.push(res + "" ); } } return Integer.parseInt(strings.pop()); } }
中缀转后缀 中缀表达式 转化为 后缀表达式 ,难度有点大,详情如下图:
中缀表达式 转化为 后缀表达式 代码实现如下:
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 String expression = "1+((20+3)*4)-5" ; List<String> list1 = toInfixExpressionList(expression); System.out.println(list1); List<String> list2 = parseSuffixExpressionList(list1); System.out.println(list2); int calculate1 = calculate(list2);System.out.println(calculate1); public static List<String> toInfixExpressionList (String s) { List<String> ls = new ArrayList<>(); int i = 0 ; String str; char c; do { if ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57 ) { ls.add("" + c); i++; } else { str = "" ; while (i < s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57 ) { str += c; i++; } ls.add(str); } } while (i < s.length()); return ls; } public static List<String> parseSuffixExpressionList (List<String> ls) { Stack<String> chStack = new Stack<>(); List<String> list = new ArrayList<>(); for (String item : ls) { if (item.matches("\\d+" )) { list.add(item); } else if (item.equals("(" )) { chStack.push(item); } else if (item.equals(")" )) { while (!chStack.peek().equals("(" )) { list.add(chStack.pop()); } chStack.pop(); } else { while (chStack.size() != 0 && Operaation.getValue(chStack.peek()) >= Operaation.getValue(item)) { list.add(chStack.pop()); } chStack.push(item); } } while (chStack.size() != 0 ) { list.add(chStack.pop()); } return list; }
逆波兰计算器完整版
逆波兰计算器完整版 代码如下:
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 194 195 196 197 198 199 200 201 202 import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.Stack;import java.util.regex.Pattern;public class ReversePolishMultiCalc { static final String SYMBOL = "\\+|-|\\*|/|\\(|\\)" ; static final String LEFT = "(" ; static final String RIGHT = ")" ; static final String ADD = "+" ; static final String MINUS= "-" ; static final String TIMES = "*" ; static final String DIVISION = "/" ; public static void main (String[] args) { String math = "12.8 + (2 - 3.55)*4+10/5.0" ; try { doCalc(doMatch(math)); } catch (Exception e) { e.printStackTrace(); } } static final int LEVEL_01 = 1 ; static final int LEVEL_02 = 2 ; static final int LEVEL_HIGH = Integer.MAX_VALUE; static Stack<String> stack = new Stack<>(); static List<String> data = Collections.synchronizedList(new ArrayList<String>()); public static String replaceAllBlank (String s ) { return s.replaceAll("\\s+" ,"" ); } public static boolean isNumber (String s) { Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$" ); return pattern.matcher(s).matches(); } public static boolean isSymbol (String s) { return s.matches(SYMBOL); } public static int calcLevel (String s) { if ("+" .equals(s) || "-" .equals(s)){ return LEVEL_01; } else if ("*" .equals(s) || "/" .equals(s)){ return LEVEL_02; } return LEVEL_HIGH; } public static List<String> doMatch (String s) throws Exception { if (s == null || "" .equals(s.trim())) throw new RuntimeException("data is empty" ); if (!isNumber(s.charAt(0 )+"" )) throw new RuntimeException("data illeagle,start not with a number" ); s = replaceAllBlank(s); String each; int start = 0 ; for (int i = 0 ; i < s.length(); i++) { if (isSymbol(s.charAt(i)+"" )){ each = s.charAt(i)+"" ; if (stack.isEmpty() || LEFT.equals(each) || ((calcLevel(each) > calcLevel(stack.peek())) && calcLevel(each) < LEVEL_HIGH)){ stack.push(each); }else if ( !stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())){ while (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek()) ){ if (calcLevel(stack.peek()) == LEVEL_HIGH){ break ; } data.add(stack.pop()); } stack.push(each); }else if (RIGHT.equals(each)){ while (!stack.isEmpty() && LEVEL_HIGH >= calcLevel(stack.peek())){ if (LEVEL_HIGH == calcLevel(stack.peek())){ stack.pop(); break ; } data.add(stack.pop()); } } start = i ; }else if ( i == s.length()-1 || isSymbol(s.charAt(i+1 )+"" ) ){ each = start == 0 ? s.substring(start,i+1 ) : s.substring(start+1 ,i+1 ); if (isNumber(each)) { data.add(each); continue ; } throw new RuntimeException("data not match number" ); } } Collections.reverse(stack); data.addAll(new ArrayList<>(stack)); System.out.println(data); return data; } public static Double doCalc (List<String> list) { Double d = 0 d; if (list == null || list.isEmpty()){ return null ; } if (list.size() == 1 ){ System.out.println(list); d = Double.valueOf(list.get(0 )); return d; } ArrayList<String> list1 = new ArrayList<>(); for (int i = 0 ; i < list.size(); i++) { list1.add(list.get(i)); if (isSymbol(list.get(i))){ Double d1 = doTheMath(list.get(i - 2 ), list.get(i - 1 ), list.get(i)); list1.remove(i); list1.remove(i-1 ); list1.set(i-2 ,d1+"" ); list1.addAll(list.subList(i+1 ,list.size())); break ; } } doCalc(list1); return d; } public static Double doTheMath (String s1,String s2,String symbol) { Double result ; switch (symbol){ case ADD : result = Double.valueOf(s1) + Double.valueOf(s2); break ; case MINUS : result = Double.valueOf(s1) - Double.valueOf(s2); break ; case TIMES : result = Double.valueOf(s1) * Double.valueOf(s2); break ; case DIVISION : result = Double.valueOf(s1) / Double.valueOf(s2); break ; default : result = null ; } return result; } }
队列知识 认识队列 队列
是一种 先进先出 的数据结构,也是常见的数据结构之一。日常生活中的 排队买东西 就是一种典型的队列。
数组模拟队列
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 public class ArrayQueueTest { public static void main (String[] args) { ArrayQueue arrayQueue = new ArrayQueue(3 ); char key = ' ' ; Scanner scanner = new Scanner(System.in); boolean loop = true ; while (loop) { System.out.println("s :显示队列(show)" ); System.out.println("e :退出程序(exit)" ); System.out.println("a :添加数据到队列(add)" ); System.out.println("g :从队列取出数据(get)" ); System.out.println("h :查看队列头数据(head)" ); key = scanner.next().charAt(0 ); switch (key) { case 's' : arrayQueue.showQueue(); break ; case 'e' : scanner.close(); loop = false ; System.out.println("程序已经退出!!!" ); System.exit(0 ); break ; case 'a' : System.out.println("请输入一个整数:" ); int value = scanner.nextInt(); arrayQueue.addQueue(value); break ; case 'g' : try { int queue = arrayQueue.getQueue(); System.out.printf("取出的数据是:%d\n" , queue); }catch (Exception e){ System.out.println(e.getMessage()); } break ; case 'h' : try { int res = arrayQueue.headQueue(); System.out.printf("队列头的数据是:%d\n" , res); }catch (Exception e){ System.out.println(e.getMessage()); } break ; default : break ; } } } } class ArrayQueue { private int maxSize; private int front; private int rear; private int [] arr; public ArrayQueue (int arrMaxSize) { maxSize = arrMaxSize; arr = new int [maxSize]; front = -1 ; rear = -1 ; } public boolean isFull () { return rear == maxSize - 1 ; } public boolean isEmpty () { return rear == front; } public void addQueue (int num) { if (isFull()) { System.out.println("队列满了,无法加入数据!!!" ); return ; } rear++; arr[rear] = num; } public int getQueue () { if (isEmpty()) { throw new RuntimeException("队列为空,不能取数据!!!" ); } front++; return arr[front]; } public void showQueue () { if (isEmpty()) { System.out.println("队列为空,没有数据!!!" ); } for (int i = 0 ; i < arr.length; i++) { System.out.printf("arr[%d] = %d\n" , i, arr[i]); } } public int headQueue () { if (isEmpty()) { throw new RuntimeException("队列为空,没有数据!!!" ); } return arr[++front]; } }
数组模拟队列
会出现一个小问题:数组不能够重复使用 。比如队列最大值为 3 ,添加 3 个数之后然后取出,再次添加就出现了队列满的情况。为了解决这个问题,就有了环形队列。接着往下看!!!
环形队列 环形队列
就是一个环,队列头和队列尾可以循环重合 ,且避免了普通队列的缺点,就是有点难理解而已,其实它的本质仍然是一个队列,一样有队列头,队列尾。它的特点一样是 先进先出(FIFO) 。
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 public class ArrayCircleQueueTest { public static void main (String[] args) { ArrayCircleQueue arrayQueue = new ArrayCircleQueue(4 ); char key = ' ' ; Scanner scanner = new Scanner(System.in); boolean loop = true ; while (loop) { System.out.println("s :显示队列(show)" ); System.out.println("e :退出程序(exit)" ); System.out.println("a :添加数据到队列(add)" ); System.out.println("g :从队列取出数据(get)" ); System.out.println("h :查看队列头数据(head)" ); key = scanner.next().charAt(0 ); switch (key) { case 's' : arrayQueue.showQueue(); break ; case 'e' : scanner.close(); loop = false ; System.out.println("程序已经退出!!!" ); System.exit(0 ); break ; case 'a' : System.out.println("请输入一个整数:" ); int value = scanner.nextInt(); arrayQueue.addQueue(value); break ; case 'g' : try { int queue = arrayQueue.getQueue(); System.out.printf("取出的数据是:%d\n" , queue); } catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'h' : try { int res = arrayQueue.headQueue(); System.out.printf("队列头的数据是:%d\n" , res); } catch (Exception e) { System.out.println(e.getMessage()); } break ; default : break ; } } } } class ArrayCircleQueue { private int maxSize; private int front; private int rear; private int [] arr; public ArrayCircleQueue (int arrMaxSize) { maxSize = arrMaxSize; arr = new int [maxSize]; front = 0 ; rear = 0 ; } public boolean isFull () { return (rear + 1 ) % maxSize == front; } public boolean isEmpty () { return rear == front; } public void addQueue (int num) { if (isFull()) { System.out.println("队列满了,无法加入数据!!!" ); return ; } arr[rear] = num; rear = (rear + 1 ) % maxSize; } public int getQueue () { if (isEmpty()) { throw new RuntimeException("队列为空,不能取数据!!!" ); } int value = arr[front]; front = (front + 1 ) % maxSize; return value; } public void showQueue () { if (isEmpty()) { System.out.println("队列为空,没有数据!!!" ); } for (int i = front; i < front + size(); i++) { System.out.printf("arr[%d] = %d\n" , i % maxSize, arr[i % maxSize]); } } public int headQueue () { if (isEmpty()) { throw new RuntimeException("队列为空,没有数据!!!" ); } return arr[front]; } public int size () { return (rear + maxSize - front) % maxSize; } }
递归和回溯 迷宫问题
迷宫问题 代码实现如下:
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 public class Maze { public static void main (String[] args) { int [][] maze = new int [8 ][7 ]; for (int i = 0 ; i < 7 ; i++) { maze[0 ][i] = 1 ; maze[7 ][i] = 1 ; } for (int i = 0 ; i < 8 ; i++) { maze[i][0 ] = 1 ; maze[i][6 ] = 1 ; } maze[3 ][1 ] = 1 ; maze[3 ][2 ] = 1 ; for (int i = 0 ; i < maze.length; i++) { for (int j = 0 ; j < 7 ; j++) { System.out.print(maze[i][j] + " " ); } System.out.println(); } findWay(maze, 1 , 1 ); System.out.println("--------------" ); for (int i = 0 ; i < maze.length; i++) { for (int j = 0 ; j < 7 ; j++) { System.out.print(maze[i][j] + " " ); } System.out.println(); } } public static boolean findWay (int [][] maze, int i, int j) { if (maze[6 ][5 ] == 2 ) { return true ; } else { if (maze[i][j] == 0 ) { maze[i][j] = 2 ; if (findWay(maze, i + 1 , j)) { return true ; } else if (findWay(maze, i, j + 1 )) { return true ; } else if (findWay(maze, i - 1 , j)) { } else if (findWay(maze, i, j - 1 )) { return true ; } else { maze[i][j] = 3 ; return false ; } } else { return false ; } } return false ; } }
八皇后问题
八皇后问题 问题代码实现如下:
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 public class Queue8 { int max = 8 ; int [] array = new int [max]; static int count = 0 ; static int judgeCount = 0 ; public static void main (String[] args) { Queue8 queue8 = new Queue8(); queue8.check(0 ); System.out.println("一共有 " + count + " 种解法!!!" ); System.out.println("一共有 " + judgeCount + " 次冲突!!!" ); } private void check (int n) { if (n == max) { print(); return ; } for (int i = 0 ; i < max; i++) { array[n] = i; if (judge(n)) { check(n + 1 ); } } } private boolean judge (int n) { judgeCount++; for (int i = 0 ; i < n; i++) { if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) { return false ; } } return true ; } public void print () { count++; for (int i = 0 ; i < array.length; i++) { System.out.print(array[i] + " " ); } System.out.println(); } }
数组和广义表 稀疏数组 基本介绍 稀疏数组
可以看做是 普通数组的压缩 ,当一个数组中 大部分元素为 0 或者为同一个值 的数组时,可以使用稀疏数组来保存该数组。
应用案例 棋盘存档案例
就是一个 稀疏数组 的实际应用案例。参考下图:
案例分析
代码实现 使用 稀疏数组 实现的 棋盘存档案例 如下:
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 public class SparseArray { public static void main (String[] args) throws Exception { int chessArray[][] = new int [11 ][11 ]; chessArray[1 ][2 ] = 1 ; chessArray[2 ][3 ] = 2 ; chessArray[4 ][5 ] = 2 ; System.out.println("原始的二维数组:\n-----------------------------------------" ); for (int [] row : chessArray) { for (int data : row) { System.out.printf("%d\t" , data); } System.out.println(); } int sum = 0 ; for (int i = 0 ; i < chessArray.length; i++) { for (int j = 0 ; j < chessArray.length; j++) { if (chessArray[i][j] != 0 ) { sum++; } } } int sparseArr[][] = new int [sum + 1 ][3 ]; sparseArr[0 ][0 ] = chessArray.length; sparseArr[0 ][1 ] = chessArray[0 ].length; sparseArr[0 ][2 ] = sum; int count = 0 ; for (int i = 0 ; i < chessArray.length; i++) { for (int j = 0 ; j < chessArray.length; j++) { if (chessArray[i][j] != 0 ) { count++; sparseArr[count][0 ] = i; sparseArr[count][1 ] = j; sparseArr[count][2 ] = chessArray[i][j]; } } } System.out.println(); System.out.println("原始二维数组转为稀疏数组后:\n-----------------------------------------" ); for (int i = 0 ; i < sparseArr.length; i++) { System.out.printf("%d\t%d\t%d\t\n" , sparseArr[i][0 ], sparseArr[i][1 ], sparseArr[i][2 ]); } System.out.println(); int chessArr[][] = new int [sparseArr[0 ][0 ]][sparseArr[0 ][1 ]]; for (int i = 1 ; i < sparseArr.length; i++) { chessArr[sparseArr[i][0 ]][sparseArr[i][1 ]] = sparseArr[i][2 ]; } System.out.println("从稀疏数组恢复到原始二维数组:\n-----------------------------------------" ); for (int [] row : chessArr) { for (int data : row) { System.out.printf("%d\t" , data); } System.out.println(); } System.out.println(); File file = new File("data.txt" ); sparseToDisk(file, sparseArr); System.out.println("从磁盘读取稀疏数组并打印:\n-----------------------------------------" ); int [][] ints = diskToSparse(file, sparseArr); for (int [] anInt : ints) { for (int i : anInt) { System.out.printf("%d\t" , i); } System.out.println(); } } public static void sparseToDisk (File file, int [][] arr) throws IOException { if (!file.exists()) { file.createNewFile(); } FileWriter writer = new FileWriter(file); for (int i = 0 ; i < arr.length; i++) { for (int j = 0 ; j < 3 ; j++) { int num = arr[i][j]; Integer integer = new Integer(num); writer.write(integer.toString() + " " ); } writer.write("\r\n" ); } writer.flush(); writer.close(); } public static int [][] diskToSparse(File file, int [][] arr) throws Exception { BufferedReader reader = new BufferedReader(new FileReader(file)); int [][] sparseArray = new int [arr.length][3 ]; for (int i = 0 ; i < arr.length; i++) { String s = reader.readLine(); String[] split = s.split(" " ); int j = 0 ; for (String s1 : split) { sparseArray[i][j++] = Integer.valueOf(s1); } } reader.close(); return sparseArray; } }
树和二叉树 树的初识 为什么需要树
树的常用术语
二叉树 二叉树的概念
二叉树的遍历
二叉树的 前序遍历
、 中序遍历
、 后序遍历
代码实现如下:
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 BinaryTreeTest { public static void main (String[] args) { BinaryTree binaryTree = new BinaryTree(); Node node1 = new Node(1 , "典韦" ); Node node2 = new Node(2 , "妲己" ); Node node3 = new Node(3 , "廉颇" ); Node node4 = new Node(4 , "亚瑟" ); Node node5 = new Node(5 , "后羿" ); Node node6 = new Node(6 , "女娲" ); Node node7 = new Node(7 , "张良" ); Node node8 = new Node(8 , "刘备" ); node1.setLeft(node2); node1.setRight(node3); node2.setLeft(node4); node2.setRight(node5); node3.setLeft(node6); node3.setRight(node7); node4.setLeft(node8); binaryTree.setRoot(node1); System.out.println("前序遍历:" ); binaryTree.preOrder(); System.out.println("=======================" ); System.out.println("中序遍历:" ); binaryTree.infixOrder(); System.out.println("=======================" ); System.out.println("后序遍历:" ); binaryTree.postOrder(); } } class BinaryTree { private Node root; public void setRoot (Node root) { this .root = root; } public void preOrder () { if (this .root != null ) { this .root.preOrder(); } else { System.out.println("The Binary Tree is null !!!" ); } } public void infixOrder () { if (this .root != null ) { this .root.infixOrder(); } else { System.out.println("The Binary Tree is null !!!" ); } } public void postOrder () { if (this .root != null ) { this .root.postOrder(); } else { System.out.println("The Binary Tree is null !!!" ); } } } class Node { private int no; private String name; private Node left; private Node right; public Node (int no, String name) { this .no = no; this .name = name; } public int getNo () { return no; } @Override public String toString () { return "Node{" + "no=" + no + ", name='" + name + '\'' + '}' ; } public void setNo (int no) { this .no = no; } public String getName () { return name; } public void setName (String name) { this .name = name; } public Node getLeft () { return left; } public void setLeft (Node left) { this .left = left; } public Node getRight () { return right; } public void setRight (Node right) { this .right = right; } public void preOrder () { System.out.println(this ); if (this .left != null ) { this .left.preOrder(); } if (this .right != null ) { this .right.preOrder(); } } public void infixOrder () { if (this .left != null ) { this .left.infixOrder(); } System.out.println(this ); if (this .right != null ) { this .right.infixOrder(); } } public void postOrder () { if (this .left != null ) { this .left.postOrder(); } if (this .right != null ) { this .right.postOrder(); } System.out.println(this ); } }
二叉树的查找
查找要求:
1、请编写前序查找,中序查找和后序查找的方法。
2、分别使用三种查找方式,查找 heroNO = 5 的节点
3、分析各种查找方式,分别比较了多少次
二叉树的 三种查找方式 代码如下:
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 Node preOrderSearch (int no) { System.out.println("前序遍历次数~~~" ); if (this .no == no) { return this ; } Node resNode = null ; if (this .left != null ) { resNode = this .left.preOrderSearch(no); } if (resNode != null ) { return resNode; } if (this .right != null ) { resNode = this .right.preOrderSearch(no); } return resNode; } public Node infixOrderSearch (int no) { Node resNode = null ; if (this .left != null ) { resNode = this .left.infixOrderSearch(no); } if (resNode != null ) { return resNode; } System.out.println("中序遍历次数~~~" ); if (this .no == no) { return this ; } if (this .right != null ) { resNode = this .right.infixOrderSearch(no); } return resNode; } public Node postOrderSearch (int no) { Node resNode = null ; if (this .left != null ) { resNode = this .left.postOrderSearch(no); } if (resNode != null ) { return resNode; } if (this .right != null ) { resNode = this .right.postOrderSearch(no); } System.out.println("后序遍历次数~~~" ); if (this .no == no) { return this ; } return resNode; } public Node preOrderSearch (int no) { if (root != null ) { return root.preOrderSearch(no); } else { return null ; } } public Node infixOrderSearch (int no) { if (root != null ) { return root.infixOrderSearch(no); } else { return null ; } } public Node postOrderSearch (int no) { if (root != null ) { return root.postOrderSearch(no); } else { return null ; } } System.out.println("前序遍历查找:" ); int findNum = 5 ;Node resNode1 = binaryTree.preOrderSearch(findNum); if (resNode1 != null ) { System.out.printf("查找成功,信息为:no = %d , name = %s" , resNode1.getNo(), resNode1.getName()); } else { System.out.printf("没有找到编号为 %d 的结点!!!" , findNum); } System.out.println("\n====================================" ); System.out.println("中序遍历查找:" ); Node resNode2 = binaryTree.infixOrderSearch(findNum); if (resNode2 != null ) { System.out.printf("查找成功,信息为:no = %d , name = %s" , resNode2.getNo(), resNode2.getName()); } else { System.out.printf("没有找到编号为 %d 的结点!!!" , findNum); } System.out.println("\n====================================" ); System.out.println("后序遍历查找:" ); Node resNode3 = binaryTree.postOrderSearch(findNum); if (resNode3 != null ) { System.out.printf("查找成功,信息为:no = %d , name = %s" , resNode3.getNo(), resNode3.getName()); } else { System.out.printf("没有找到编号为 %d 的结点!!!" , findNum); }
二叉树的删除
注意:
非叶子结点的 删除操作 遵照上图的规定,不同的删除策略会导致结果不同。
二叉树的 删除操作 代码如下:
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 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); } } public void delNode (int no) { if (root != null ) { if (root.getNo() == no) { root = null ; } else { root.delNode(no); } } else { System.out.println("空树,不能删除!!!" ); } } System.out.println("删除前:" ); binaryTree.preOrder(); binaryTree.delNode(findNum); System.out.println("删除后:" ); binaryTree.preOrder();
顺序存储二叉树
顺序存储二叉树 代码实现如下:
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 public class ArrayBinaryTreeTest { public static void main (String[] args) { int [] arr = {1 , 2 , 3 , 4 , 5 , 6 , 7 }; ArrayBinaryTree arrayBinaryTree = new ArrayBinaryTree(arr); arrayBinaryTree.preOrder(); } } class ArrayBinaryTree { private int [] arr; public ArrayBinaryTree (int [] arr) { this .arr = arr; } public void preOrder () { this .preOrder(0 ); } public void preOrder (int index) { if (arr == null || arr.length == 0 ) { System.out.println("The array is empty !!!" ); } System.out.println(arr[index]); if ((index * 2 + 1 ) < arr.length) { preOrder(2 * index + 1 ); } if ((index * 2 + 2 ) < arr.length) { preOrder(2 * index + 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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 public class ThreadedBinaryTreeTest { public static void main (String[] args) { Node node1 = new Node(1 , "典韦" ); Node node2 = new Node(3 , "廉颇" ); Node node3 = new Node(6 , "女娲" ); Node node4 = new Node(8 , "刘备" ); Node node5 = new Node(10 , "妲己" ); Node node6 = new Node(14 , "亚瑟" ); node1.setLeft(node2); node1.setRight(node3); node2.setLeft(node4); node2.setRight(node5); node3.setLeft(node6); ThreadedBinaryTree tbt = new ThreadedBinaryTree(); tbt.setRoot(node1); tbt.threadedNode(); Node leftNode = node5.getLeft(); Node rightNode = node5.getRight(); System.out.println("10 号节点的前驱结点是: " + leftNode); System.out.println("10 号节点的后继结点是: " + rightNode); } } class ThreadedBinaryTree { private Node root; private Node pre = null ; public void setRoot (Node root) { this .root = root; } public void threadedNode () { this .threadedNode(root); } public void threadedNode (Node node) { if (node == null ) { System.out.println("node is null, so it is not be operated !!!" ); return ; } threadedNode(node.getLeft()); if (node.getLeft() == null ) { node.setLeft(pre); node.setLeftType(1 ); } if (pre != null && pre.getRight() == null ) { pre.setRight(node); pre.setRightType(1 ); } pre = node; threadedNode(node.getRight()); } public void preOrder () { if (this .root != null ) { this .root.preOrder(); } else { System.out.println("The Binary Tree is null !!!" ); } } public void infixOrder () { if (this .root != null ) { this .root.infixOrder(); } else { System.out.println("The Binary Tree is null !!!" ); } } public void postOrder () { if (this .root != null ) { this .root.postOrder(); } else { System.out.println("The Binary Tree is null !!!" ); } } public Node preOrderSearch (int no) { if (root != null ) { return root.preOrderSearch(no); } else { return null ; } } public Node infixOrderSearch (int no) { if (root != null ) { return root.infixOrderSearch(no); } else { return null ; } } public Node postOrderSearch (int no) { if (root != null ) { return root.postOrderSearch(no); } else { return null ; } } public void delNode (int no) { if (root != null ) { if (root.getNo() == no) { root = null ; } else { root.delNode(no); } } else { System.out.println("空树,不能删除!!!" ); } } } class Node { private int no; private String name; private Node left; private Node right; private int leftType; private int rightType; public int getLeftType () { return leftType; } public void setLeftType (int leftType) { this .leftType = leftType; } public int getRightType () { return rightType; } public void setRightType (int rightType) { this .rightType = rightType; } public Node (int no, String name) { this .no = no; this .name = name; } public int getNo () { return no; } @Override public String toString () { return "Node{" + "no=" + no + ", name='" + name + '\'' + '}' ; } public void setNo (int no) { this .no = no; } public String getName () { return name; } public void setName (String name) { this .name = name; } public Node getLeft () { return left; } public void setLeft (Node left) { this .left = left; } public Node getRight () { return right; } public void setRight (Node right) { this .right = right; } public void preOrder () { System.out.println(this ); if (this .left != null ) { this .left.preOrder(); } if (this .right != null ) { this .right.preOrder(); } } public void infixOrder () { if (this .left != null ) { this .left.infixOrder(); } System.out.println(this ); if (this .right != null ) { this .right.infixOrder(); } } public void postOrder () { if (this .left != null ) { this .left.postOrder(); } if (this .right != null ) { this .right.postOrder(); } System.out.println(this ); } public Node preOrderSearch (int no) { System.out.println("前序遍历次数~~~" ); if (this .no == no) { return this ; } Node resNode = null ; if (this .left != null ) { resNode = this .left.preOrderSearch(no); } if (resNode != null ) { return resNode; } if (this .right != null ) { resNode = this .right.preOrderSearch(no); } return resNode; } public Node infixOrderSearch (int no) { Node resNode = null ; if (this .left != null ) { resNode = this .left.infixOrderSearch(no); } if (resNode != null ) { return resNode; } System.out.println("中序遍历次数~~~" ); if (this .no == no) { return this ; } if (this .right != null ) { resNode = this .right.infixOrderSearch(no); } return resNode; } public Node postOrderSearch (int no) { Node resNode = null ; if (this .left != null ) { resNode = this .left.postOrderSearch(no); } if (resNode != null ) { return resNode; } if (this .right != null ) { resNode = this .right.postOrderSearch(no); } System.out.println("后序遍历次数~~~" ); if (this .no == no) { return this ; } return resNode; } 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); } } }
线索化二叉树构建好了,那么如何遍历呢。如下图:
线索化二叉树的遍历 代码如下:
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 tbt.threadedList(); public void threadedList () { Node temp = root; while (temp != null ) { while (temp.getLeftType() == 0 ) { temp = temp.getLeft(); } System.out.println(temp); while (temp.getRightType() == 1 ){ temp = temp.getRight(); System.out.println(temp); } temp = temp.getRight(); } }
树的应用-堆 堆的介绍 堆(Heap)
是计算机科学中一类特殊的数据结构的统称。 堆
通常是一个可以被看做一棵 完全二叉树 的数组对象。【———— 百度百科】
堆的算法思想:
不必将值一个个地插入堆中,通过交换形成堆。假设一个小根堆的左、右子树都已是堆,并且根的元素名为 root ,其左右子节点为 left 和 right ,这种情况下,有两种可能:
root <= left 并且 root <= right ,此时堆已完成;
root >= left 或者 root >= right ,此时 root 应与两个子女中值较小的一个交换,结果得到一个堆,除非 root 仍然大于其新子女的一个或全部的两个。这种情况下,我们只需简单地继续这种将 root “拉下来”的过程,直至到达某一个层使它小于它的子女,或者它成了叶结点。
堆排序 堆排序
是一种选择排序 ,是利用 堆
这种数据结构而设计的一种排序算法。具体介绍如下图:
堆排序 的代码实现如下:
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 public class HeapSort { public static void main (String[] args) { int [] arr = {4 , 6 , 8 , 5 , 9 }; heapSort(arr); } public static void heapSort (int [] arr) { int temp = 0 ; System.out.println("堆排序!" ); for (int i = arr.length / 2 - 1 ; i >= 0 ; i--) { adjustHeap(arr, i, arr.length); } for (int j = arr.length - 1 ; j > 0 ; j--) { temp = arr[j]; arr[j] = arr[0 ]; arr[0 ] = temp; adjustHeap(arr, 0 , j); } System.out.println(Arrays.toString(arr)); } public static void adjustHeap (int [] arr, int i, int length) { int temp = arr[i]; for (int k = 2 * i + 1 ; k < length; k = k * 2 + 1 ) { if ((k + 1 ) < length && arr[k] < arr[k + 1 ]) { k++; } if (arr[k] > temp) { arr[i] = arr[k]; i = k; } else { break ; } } arr[i] = temp; } }
堆排序的性能测试 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static void main (String[] args) { int [] arr = new int [8000000 ]; for (int i = 0 ; i < arr.length; i++) { arr[i] = (int )(Math.random() * 100000 + 1 ); } long start = System.currentTimeMillis(); heapSort(arr); long end = System.currentTimeMillis(); System.out.println("排序 800 万个数据需要 " + (end - start) / 1000 + " 秒 " + (end - start) % 1000 + " 毫秒" ); }
赫夫曼树 基本介绍 赫夫曼树的基本介绍 如下图:
赫夫曼树的构建
赫夫曼树的构建 的代码实现如下:
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 public class HuffmanTree { public static void main (String[] args) { int [] arr = {13 , 7 , 8 , 3 , 29 , 6 , 1 }; Node root = createHuffmanTree(arr); preOrder(root); } public static void preOrder (Node root) { if (root != null ) { root.preOrder(); } else { System.out.println("该赫夫曼树是空树,无法遍历~~~" ); } } public static Node createHuffmanTree (int [] arr) { List<Node> nodes = new ArrayList<>(); for (int value : arr) { nodes.add(new Node(value)); } while (nodes.size() > 1 ) { Collections.sort(nodes); Node leftNode = nodes.get(0 ); Node rightNode = nodes.get(1 ); Node parent = new Node(leftNode.value + rightNode.value); parent.left = leftNode; parent.right = rightNode; nodes.remove(leftNode); nodes.remove(rightNode); nodes.add(parent); } return nodes.get(0 ); } } class Node implements Comparable <Node > { int value; Node left; Node right; public void preOrder () { System.out.println(this ); if (this .left != null ) { this .left.preOrder(); } if (this .right != null ) { this .right.preOrder(); } } @Override public String toString () { return "Node{" + "value=" + value + '}' ; } public Node (int value) { this .value = value; } @Override public int compareTo (Node o) { return this .value - o.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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 public class HuffmanCode { public static void main (String[] args) { String str = "i like like like java do you like a java" ; byte [] bytes = str.getBytes(); System.out.println(bytes.length); List<Node> nodes = getNodes(bytes); Node root = createHuffmanTree(nodes); root.preOrder(); } public static List<Node> getNodes (byte [] bytes) { List<Node> nodes = new ArrayList<>(); Map<Byte, Integer> map = new HashMap<>(); for (byte val : bytes) { Integer count = map.get(val); if (count == null ) { map.put(val, 1 ); } else { map.put(val, count + 1 ); } } for (Map.Entry<Byte, Integer> entry : map.entrySet()) { nodes.add(new Node(entry.getKey(), entry.getValue())); } return nodes; } public static Node createHuffmanTree (List<Node> nodes) { while (nodes.size() > 1 ) { Collections.sort(nodes); Node leftNode = nodes.get(0 ); Node rightNode = nodes.get(1 ); Node parent = new Node(null , leftNode.weight + rightNode.weight); parent.left = leftNode; parent.right = rightNode; nodes.remove(leftNode); nodes.remove(rightNode); nodes.add(parent); } return nodes.get(0 ); } } class Node implements Comparable <Node > { Byte data; int weight; Node left; Node right; public Node (Byte data, int weight) { this .data = data; this .weight = weight; } @Override public String toString () { return "Node{" + "data=" + data + ", weight=" + weight + '}' ; } @Override public int compareTo (Node o) { return this .weight - o.weight; } public void preOrder () { System.out.println(this ); if (this .left != null ) { this .left.preOrder(); } if (this .right != null ) { this .right.preOrder(); } } }
数据压缩第二步:
根据赫夫曼树生成赫夫曼编码。 代码如下:
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 public static void main (String[] args) { String str = "i like like like java do you like a java" ; byte [] bytes = str.getBytes(); System.out.println(bytes.length); List<Node> nodes = getNodes(bytes); Node root = createHuffmanTree(nodes); root.preOrder(); getCodes(root); System.out.println(huffmanCodes); } public static Map<Byte, String> getCodes (Node root) { if (root == null ) { return null ; } getCodes(root.left, "0" , stringBuilder); getCodes(root.right, "1" , stringBuilder); return huffmanCodes; } static Map<Byte, String> huffmanCodes = new HashMap<>();static StringBuilder stringBuilder = new StringBuilder();public static void getCodes (Node node, String code, StringBuilder stringBuilder) { StringBuilder stringBuilder1 = new StringBuilder(stringBuilder); stringBuilder1.append(code); if (node != null ) { if (node.data == null ) { getCodes(node.left, "0" , stringBuilder1); getCodes(node.right, "1" , stringBuilder1); } else { huffmanCodes.put(node.data, stringBuilder1.toString()); } } }
数据压缩第三步:
根据赫夫曼编码压缩数据(无损压缩)。 完整的代码如下:
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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 public class HuffmanCode { public static void main (String[] args) { String str = "i like like like java do you like a java" ; byte [] bytes = str.getBytes(); System.out.println("压缩前的长度是:" + bytes.length); byte [] huffmanBytes = huffmanZip(bytes); System.out.println("压缩后的结果是:" + Arrays.toString(huffmanBytes)); System.out.println("压缩后的长度是:" + huffmanBytes.length); System.out.println("求出的压缩率是:" + (float ) (bytes.length - huffmanBytes.length) / bytes.length * 100 + "%" ); } public static byte [] huffmanZip(byte [] bytes) { List<Node> nodes = getNodes(bytes); Node root = createHuffmanTree(nodes); Map<Byte, String> huffmanCodes = getCodes(root); byte [] huffmanCodeBytes = zip(bytes, huffmanCodes); return huffmanCodeBytes; } public static byte [] zip(byte [] bytes, Map<Byte, String> huffmanCodes) { StringBuilder stringBuilder = new StringBuilder(); for (byte aByte : bytes) { stringBuilder.append(huffmanCodes.get(aByte)); } int len; if (stringBuilder.length() % 8 == 0 ) { len = stringBuilder.length() / 8 ; } else { len = stringBuilder.length() / 8 + 1 ; } byte [] huffmanCodeBytes = new byte [len]; int index = 0 ; for (int i = 0 ; i < stringBuilder.length(); i += 8 ) { String strByte; if (i + 8 > stringBuilder.length()) { strByte = stringBuilder.substring(i); } else { strByte = stringBuilder.substring(i, i + 8 ); } huffmanCodeBytes[index] = (byte ) Integer.parseInt(strByte, 2 ); index++; } return huffmanCodeBytes; } public static Map<Byte, String> getCodes (Node root) { if (root == null ) { return null ; } getCodes(root.left, "0" , stringBuilder); getCodes(root.right, "1" , stringBuilder); return huffmanCodes; } static Map<Byte, String> huffmanCodes = new HashMap<>(); static StringBuilder stringBuilder = new StringBuilder(); public static void getCodes (Node node, String code, StringBuilder stringBuilder) { StringBuilder stringBuilder1 = new StringBuilder(stringBuilder); stringBuilder1.append(code); if (node != null ) { if (node.data == null ) { getCodes(node.left, "0" , stringBuilder1); getCodes(node.right, "1" , stringBuilder1); } else { huffmanCodes.put(node.data, stringBuilder1.toString()); } } } public static List<Node> getNodes (byte [] bytes) { List<Node> nodes = new ArrayList<>(); Map<Byte, Integer> map = new HashMap<>(); for (byte val : bytes) { Integer count = map.get(val); if (count == null ) { map.put(val, 1 ); } else { map.put(val, count + 1 ); } } for (Map.Entry<Byte, Integer> entry : map.entrySet()) { nodes.add(new Node(entry.getKey(), entry.getValue())); } return nodes; } public static Node createHuffmanTree (List<Node> nodes) { while (nodes.size() > 1 ) { Collections.sort(nodes); Node leftNode = nodes.get(0 ); Node rightNode = nodes.get(1 ); Node parent = new Node(null , leftNode.weight + rightNode.weight); parent.left = leftNode; parent.right = rightNode; nodes.remove(leftNode); nodes.remove(rightNode); nodes.add(parent); } return nodes.get(0 ); } } class Node implements Comparable <Node > { Byte data; int weight; Node left; Node right; public Node (Byte data, int weight) { this .data = data; this .weight = weight; } @Override public String toString () { return "Node{" + "data=" + data + ", weight=" + weight + '}' ; } @Override public int compareTo (Node o) { return this .weight - o.weight; } public void preOrder () { System.out.println(this ); if (this .left != null ) { this .left.preOrder(); } if (this .right != null ) { this .right.preOrder(); } } }
赫夫曼应用-数据解压
数据的解压 的代码如下:
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 public static void main (String[] args) { String str = "i like like like java do you like a java" ; byte [] bytes = str.getBytes(); System.out.println("压缩前的长度是:" + bytes.length); byte [] huffmanBytes = huffmanZip(bytes); System.out.println("压缩后的结果是:" + Arrays.toString(huffmanBytes)); System.out.println("压缩后的长度是:" + huffmanBytes.length); System.out.println("求出的压缩率是:" + (float ) (bytes.length - huffmanBytes.length) / bytes.length * 100 + "%" ); byte [] sourceStr = decode(huffmanCodes, huffmanBytes); System.out.println(new String(sourceStr)); } public static byte [] decode(Map<Byte, String> huffmanCodes, byte [] huffmanBytes) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0 ; i < huffmanBytes.length; i++) { byte huffmanByte = huffmanBytes[i]; boolean flag = (i == huffmanBytes.length - 1 ); stringBuilder.append(byteToBitString(!flag, huffmanByte)); } System.out.println(stringBuilder.toString()); Map<String, Byte> map = new HashMap<>(); for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) { map.put(entry.getValue(), entry.getKey()); } System.out.println(map); List<Byte> list = new ArrayList<>(); for (int i = 0 ; i < stringBuilder.length();) { int count = 1 ; boolean flag = true ; Byte b = null ; while (flag) { String key = stringBuilder.substring(i, i + count); b = map.get(key); if (b == null ) { count++; } else { flag = false ; } } list.add(b); i += count; } byte [] bytes = new byte [list.size()]; for (int i = 0 ; i < bytes.length; i++) { bytes[i] = list.get(i); } return bytes; } public static String byteToBitString (boolean flag, byte b) { int temp = b; if (flag) { temp |= 256 ; } String str = Integer.toBinaryString(temp); if (flag) { return str.substring(str.length() - 8 ); } else { return str; } }
赫夫曼应用-文件压缩 课件图片下载 课件图片下载
文件压缩 代码如下:
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 static void main (String[] args) { String str = "i like like like java do you like a java" ; byte [] bytes = str.getBytes(); System.out.println("压缩前的长度是:" + bytes.length); String src = "F:\\src.jpg" ; String desc = "F:\\dest.zip" ; zipFile(src, desc); } public static void zipFile (String srcFile, String destFile) { OutputStream os = null ; ObjectOutputStream oos = null ; FileInputStream fis = null ; try { fis = new FileInputStream(srcFile); byte [] bytes = new byte [fis.available()]; fis.read(bytes); byte [] huffmanBytes = huffmanZip(bytes); os = new FileOutputStream(destFile); oos = new ObjectOutputStream(os); oos.writeObject(huffmanBytes); oos.writeObject(huffmanCodes); } catch (Exception e) { System.out.println(e.getMessage()); } finally { try { oos.close(); os.close(); fis.close(); } catch (Exception e) { System.out.println(e.getMessage()); } } }
赫夫曼应用-文件解压
文件解压 代码如下:
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 static void main (String[] args) { String str = "i like like like java do you like a java" ; byte [] bytes = str.getBytes(); System.out.println("压缩前的长度是:" + bytes.length); String src = "F:\\src.jpg" ; String desc = "F:\\dest.zip" ; unZipFile(desc, src); } public static void unZipFile (String zipFile, String destFile) { InputStream is = null ; ObjectInputStream ois = null ; OutputStream os = null ; try { is = new FileInputStream(zipFile); ois = new ObjectInputStream(is); byte [] huffmanBytes = (byte []) ois.readObject(); Map<Byte, String> huffmanCodes = (Map<Byte, String>) ois.readObject(); byte [] bytes = decode(huffmanCodes, huffmanBytes); os = new FileOutputStream(destFile); os.write(bytes); } catch (Exception e) { System.out.println(e.getMessage()); } finally { try { os.close(); ois.close(); is.close(); } catch (Exception e) { System.out.println(e.getMessage()); } } }
赫夫曼编码注意事项
赫夫曼编码部分的所有完整代码如下:
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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 import java.io.*;import java.util.*;public class HuffmanCode { static Map<Byte, String> huffmanCodes = new HashMap<>(); static StringBuilder stringBuilder = new StringBuilder(); public static void main (String[] args) { String str = "i like like like java do you like a java" ; byte [] bytes = str.getBytes(); System.out.println("压缩前的长度是:" + bytes.length); String src = "F:\\src2.jpg" ; String desc = "F:\\dest.zip" ; unZipFile(desc, src); } public static void unZipFile (String zipFile, String destFile) { InputStream is = null ; ObjectInputStream ois = null ; OutputStream os = null ; try { is = new FileInputStream(zipFile); ois = new ObjectInputStream(is); byte [] huffmanBytes = (byte []) ois.readObject(); Map<Byte, String> huffmanCodes = (Map<Byte, String>) ois.readObject(); byte [] bytes = decode(huffmanCodes, huffmanBytes); os = new FileOutputStream(destFile); os.write(bytes); } catch (Exception e) { System.out.println(e.getMessage()); } finally { try { os.close(); ois.close(); is.close(); } catch (Exception e) { System.out.println(e.getMessage()); } } } public static void zipFile (String srcFile, String destFile) { OutputStream os = null ; ObjectOutputStream oos = null ; FileInputStream fis = null ; try { fis = new FileInputStream(srcFile); byte [] bytes = new byte [fis.available()]; fis.read(bytes); byte [] huffmanBytes = huffmanZip(bytes); os = new FileOutputStream(destFile); oos = new ObjectOutputStream(os); oos.writeObject(huffmanBytes); oos.writeObject(huffmanCodes); } catch (Exception e) { System.out.println(e.getMessage()); } finally { try { oos.close(); os.close(); fis.close(); } catch (Exception e) { System.out.println(e.getMessage()); } } } public static byte [] decode(Map<Byte, String> huffmanCodes, byte [] huffmanBytes) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0 ; i < huffmanBytes.length; i++) { byte huffmanByte = huffmanBytes[i]; boolean flag = (i == huffmanBytes.length - 1 ); stringBuilder.append(byteToBitString(!flag, huffmanByte)); } System.out.println(stringBuilder.toString()); Map<String, Byte> map = new HashMap<>(); for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) { map.put(entry.getValue(), entry.getKey()); } System.out.println(map); List<Byte> list = new ArrayList<>(); for (int i = 0 ; i < stringBuilder.length(); ) { int count = 1 ; boolean flag = true ; Byte b = null ; while (flag) { String key = stringBuilder.substring(i, i + count); b = map.get(key); if (b == null ) { count++; } else { flag = false ; } } list.add(b); i += count; } byte [] bytes = new byte [list.size()]; for (int i = 0 ; i < bytes.length; i++) { bytes[i] = list.get(i); } return bytes; } public static String byteToBitString (boolean flag, byte b) { int temp = b; if (flag) { temp |= 256 ; } String str = Integer.toBinaryString(temp); if (flag) { return str.substring(str.length() - 8 ); } else { return str; } } public static byte [] huffmanZip(byte [] bytes) { List<Node> nodes = getNodes(bytes); Node root = createHuffmanTree(nodes); Map<Byte, String> huffmanCodes = getCodes(root); byte [] huffmanCodeBytes = zip(bytes, huffmanCodes); return huffmanCodeBytes; } public static byte [] zip(byte [] bytes, Map<Byte, String> huffmanCodes) { StringBuilder stringBuilder = new StringBuilder(); for (byte aByte : bytes) { stringBuilder.append(huffmanCodes.get(aByte)); } System.out.println(stringBuilder.toString()); int len; if (stringBuilder.length() % 8 == 0 ) { len = stringBuilder.length() / 8 ; } else { len = stringBuilder.length() / 8 + 1 ; } byte [] huffmanCodeBytes = new byte [len]; int index = 0 ; for (int i = 0 ; i < stringBuilder.length(); i += 8 ) { String strByte; if (i + 8 > stringBuilder.length()) { strByte = stringBuilder.substring(i); } else { strByte = stringBuilder.substring(i, i + 8 ); } huffmanCodeBytes[index] = (byte ) Integer.parseInt(strByte, 2 ); index++; } return huffmanCodeBytes; } public static Map<Byte, String> getCodes (Node root) { if (root == null ) { return null ; } getCodes(root.left, "0" , stringBuilder); getCodes(root.right, "1" , stringBuilder); return huffmanCodes; } public static void getCodes (Node node, String code, StringBuilder stringBuilder) { StringBuilder stringBuilder1 = new StringBuilder(stringBuilder); stringBuilder1.append(code); if (node != null ) { if (node.data == null ) { getCodes(node.left, "0" , stringBuilder1); getCodes(node.right, "1" , stringBuilder1); } else { huffmanCodes.put(node.data, stringBuilder1.toString()); } } } public static List<Node> getNodes (byte [] bytes) { List<Node> nodes = new ArrayList<>(); Map<Byte, Integer> map = new HashMap<>(); for (byte val : bytes) { Integer count = map.get(val); if (count == null ) { map.put(val, 1 ); } else { map.put(val, count + 1 ); } } for (Map.Entry<Byte, Integer> entry : map.entrySet()) { nodes.add(new Node(entry.getKey(), entry.getValue())); } return nodes; } public static Node createHuffmanTree (List<Node> nodes) { while (nodes.size() > 1 ) { Collections.sort(nodes); Node leftNode = nodes.get(0 ); Node rightNode = nodes.get(1 ); Node parent = new Node(null , leftNode.weight + rightNode.weight); parent.left = leftNode; parent.right = rightNode; nodes.remove(leftNode); nodes.remove(rightNode); nodes.add(parent); } return nodes.get(0 ); } } class Node implements Comparable <Node > { Byte data; int weight; Node left; Node right; public Node (Byte data, int weight) { this .data = data; this .weight = weight; } @Override public String toString () { return "Node{" + "data=" + data + ", weight=" + weight + '}' ; } @Override public int compareTo (Node o) { return this .weight - o.weight; } public void preOrder () { System.out.println(this ); if (this .left != null ) { this .left.preOrder(); } if (this .right != null ) { this .right.preOrder(); } } }
二叉排序树(BST) 基本介绍 二叉排序树
整合了 数组
和 链表
的优点 ,从而对数据的 CRUD 操作更为高效。详情如下:
创建和遍历
二叉排序树的创建和遍历 代码如下:
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 public class BinarySortTreeTest { public static void main (String[] args) { int [] arr = {7 , 3 , 10 , 12 , 5 , 1 , 9 }; BinarySortTree binarySortTree = new BinarySortTree(); for (int i = 0 ; i < arr.length; i++) { binarySortTree.add(new Node(arr[i])); } binarySortTree.infixOrder(); } } class BinarySortTree { private Node root; public void add (Node node) { if (root == null ) { root = node; } else { root.add(node); } } public void infixOrder () { if (root != null ) { root.infixOrder(); } else { System.out.println("The Binary Sort Tree is empty, so it can not be traversal!!!" ); } } } 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); } } } @Override public String toString () { return "Node{" + "value=" + value + '}' ; } public void infixOrder () { if (this .left != null ) { this .left.infixOrder(); } System.out.println(this ); if (this .right != null ) { this .right.infixOrder(); } } }
删除节点 二叉排序树
的 删除节点的情况和思路分析 如下图:
第一种情况:
删除叶子节点 。相关代码如下:
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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 public class BinarySortTreeTest { public static void main (String[] args) { int [] arr = {7 , 3 , 10 , 12 , 5 , 1 , 9 , 2 }; BinarySortTree binarySortTree = new BinarySortTree(); for (int i = 0 ; i < arr.length; i++) { binarySortTree.add(new Node(arr[i])); } binarySortTree.infixOrder(); binarySortTree.delNode(12 ); System.out.println("======================" ); binarySortTree.infixOrder(); } } class BinarySortTree { private Node root; public Node search (int value) { if (root == null ) { return null ; } else { return root.search(value); } } public Node searchParent (int value) { if (root == null ) { return null ; } else { return root.searchParent(value); } } public void delNode (int value) { if (root == null ) { return ; } else { Node targetNode = search(value); if (targetNode == null ) { return ; } if (root.left == null && root.right == null ) { root = null ; return ; } Node parent = searchParent(value); if (targetNode.left == null && targetNode.right == null ) { if (parent.left != null && parent.left.value == value) { parent.left = null ; } else if (parent.right != null && parent.right.value == value) { parent.right = null ; } } } } public void add (Node node) { if (root == null ) { root = node; } else { root.add(node); } } public void infixOrder () { if (root != null ) { root.infixOrder(); } else { System.out.println("The Binary Sort Tree is empty, so it can not be traversal!!!" ); } } } class Node { int value; Node left; Node right; public Node (int value) { this .value = value; } public Node search (int value) { if (value == this .value) { return this ; } else if (value < this .value) { if (this .left == null ) { return null ; } return this .left.search(value); } else { if (this .right == null ) { return null ; } return this .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 (value < this .value && this .left != null ) { return this .left.searchParent(value); } else if (value >= this .value && this .right != null ) { return this .right.searchParent(value); } else { return null ; } } } 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); } } } @Override public String toString () { return "Node{" + "value=" + value + '}' ; } public void infixOrder () { if (this .left != null ) { this .left.infixOrder(); } System.out.println(this ); if (this .right != null ) { this .right.infixOrder(); } } }
第二种情况:
删除只有一颗子树的节点 。相关代码如下:
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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 public class BinarySortTreeTest { public static void main (String[] args) { int [] arr = {7 , 3 , 10 , 12 , 5 , 1 , 9 , 2 }; BinarySortTree binarySortTree = new BinarySortTree(); for (int i = 0 ; i < arr.length; i++) { binarySortTree.add(new Node(arr[i])); } binarySortTree.infixOrder(); binarySortTree.delNode(1 ); System.out.println("======================" ); binarySortTree.infixOrder(); } } class BinarySortTree { private Node root; public Node search (int value) { if (root == null ) { return null ; } else { return root.search(value); } } public Node searchParent (int value) { if (root == null ) { return null ; } else { return root.searchParent(value); } } public void delNode (int value) { if (root == null ) { return ; } else { Node targetNode = search(value); if (targetNode == null ) { return ; } if (root.left == null && root.right == null ) { root = null ; return ; } Node parent = searchParent(value); if (targetNode.left == null && targetNode.right == null ) { if (parent.left != null && parent.left.value == value) { parent.left = null ; } else if (parent.right != null && parent.right.value == value) { parent.right = null ; } } else if (targetNode.left != null && targetNode.right != null ) { } else { if (targetNode.left != null ) { if (parent.left.value == value) { parent.left = targetNode.left; } else { parent.right = targetNode.left; } } else { if (parent.left.value == value) { parent.left = targetNode.right; } else { parent.right = targetNode.right; } } } } } public void add (Node node) { if (root == null ) { root = node; } else { root.add(node); } } public void infixOrder () { if (root != null ) { root.infixOrder(); } else { System.out.println("The Binary Sort Tree is empty, so it can not be traversal!!!" ); } } } class Node { int value; Node left; Node right; public Node (int value) { this .value = value; } public Node search (int value) { if (value == this .value) { return this ; } else if (value < this .value) { if (this .left == null ) { return null ; } return this .left.search(value); } else { if (this .right == null ) { return null ; } return this .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 (value < this .value && this .left != null ) { return this .left.searchParent(value); } else if (value >= this .value && this .right != null ) { return this .right.searchParent(value); } else { return null ; } } } 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); } } } @Override public String toString () { return "Node{" + "value=" + value + '}' ; } public void infixOrder () { if (this .left != null ) { this .left.infixOrder(); } System.out.println(this ); if (this .right != null ) { this .right.infixOrder(); } } }
第三种情况:
删除有两颗子树的节点 。相关代码如下:
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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 public class BinarySortTreeTest { public static void main (String[] args) { int [] arr = {7 , 3 , 10 , 12 , 5 , 1 , 9 , 2 }; BinarySortTree binarySortTree = new BinarySortTree(); for (int i = 0 ; i < arr.length; i++) { binarySortTree.add(new Node(arr[i])); } binarySortTree.infixOrder(); binarySortTree.delNode(7 ); System.out.println("======================" ); binarySortTree.infixOrder(); } } class BinarySortTree { private Node root; public Node search (int value) { if (root == null ) { return null ; } else { return root.search(value); } } public Node searchParent (int value) { if (root == null ) { return null ; } else { return root.searchParent(value); } } public int delRightTreeMin (Node node) { Node temp = node; while (temp.left != null ) { temp = temp.left; } delNode(temp.value); return temp.value; } public void delNode (int value) { if (root == null ) { return ; } else { Node targetNode = search(value); if (targetNode == null ) { return ; } if (root.left == null && root.right == null ) { root = null ; return ; } Node parent = searchParent(value); if (targetNode.left == null && targetNode.right == null ) { if (parent.left != null && parent.left.value == value) { parent.left = null ; } else if (parent.right != null && parent.right.value == value) { parent.right = null ; } } else if (targetNode.left != null && targetNode.right != null ) { int minVal = delRightTreeMin(targetNode.right); targetNode.value = minVal; } else { if (targetNode.left != null ) { if (parent != null ) { if (parent.left.value == value) { parent.left = targetNode.left; } else { parent.right = targetNode.left; } } else { root = targetNode.left; } } else { if (parent != null ) { if (parent.left.value == value) { parent.left = targetNode.right; } else { parent.right = targetNode.right; } } else { root = targetNode.right; } } } } } public void add (Node node) { if (root == null ) { root = node; } else { root.add(node); } } public void infixOrder () { if (root != null ) { root.infixOrder(); } else { System.out.println("The Binary Sort Tree is empty, so it can not be traversal!!!" ); } } } class Node { int value; Node left; Node right; public Node (int value) { this .value = value; } public Node search (int value) { if (value == this .value) { return this ; } else if (value < this .value) { if (this .left == null ) { return null ; } return this .left.search(value); } else { if (this .right == null ) { return null ; } return this .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 (value < this .value && this .left != null ) { return this .left.searchParent(value); } else if (value >= this .value && this .right != null ) { return this .right.searchParent(value); } else { return null ; } } } 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); } } } @Override public String toString () { return "Node{" + "value=" + value + '}' ; } public void infixOrder () { if (this .left != null ) { this .left.infixOrder(); } System.out.println(this ); if (this .right != null ) { this .right.infixOrder(); } } }
平衡二叉树(AVL) 基本介绍 二叉排序树 有的时候是有些问题的,这时就需要用到 平衡二叉树(AVL)
了。基本介绍如下:
创建和遍历 以下是 创建平衡二叉树过程中需要用到的三种解决方案 ,如下图:
获得树的高度、左子树的高度和右子树的高度。 代码如下:
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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 public class AVLTreeTest { public static void main (String[] args) { int [] arr = {4 , 3 , 6 , 5 , 7 , 8 }; AVLTree avlTree = new AVLTree(); for (int i = 0 ; i < arr.length; i++) { avlTree.add(new Node(arr[i])); } avlTree.infixOrder(); Node root = avlTree.getRoot(); System.out.println("树的高度 = " + root.height()); System.out.println("树的左子树高度 = " + root.leftHeight()); System.out.println("树的右子树高度 = " + root.rightHeight()); } } class AVLTree { private Node root; public Node getRoot () { return this .root; } public Node search (int value) { if (root == null ) { return null ; } else { return root.search(value); } } public Node searchParent (int value) { if (root == null ) { return null ; } else { return root.searchParent(value); } } public int delRightTreeMin (Node node) { Node temp = node; while (temp.left != null ) { temp = temp.left; } delNode(temp.value); return temp.value; } public void delNode (int value) { if (root == null ) { return ; } else { Node targetNode = search(value); if (targetNode == null ) { return ; } if (root.left == null && root.right == null ) { root = null ; return ; } Node parent = searchParent(value); if (targetNode.left == null && targetNode.right == null ) { if (parent.left != null && parent.left.value == value) { parent.left = null ; } else if (parent.right != null && parent.right.value == value) { parent.right = null ; } } else if (targetNode.left != null && targetNode.right != null ) { int minVal = delRightTreeMin(targetNode.right); targetNode.value = minVal; } else { if (targetNode.left != null ) { if (parent != null ) { if (parent.left.value == value) { parent.left = targetNode.left; } else { parent.right = targetNode.left; } } else { root = targetNode.left; } } else { if (parent != null ) { if (parent.left.value == value) { parent.left = targetNode.right; } else { parent.right = targetNode.right; } } else { root = targetNode.right; } } } } } public void add (Node node) { if (root == null ) { root = node; } else { root.add(node); } } public void infixOrder () { if (root != null ) { root.infixOrder(); } else { System.out.println("The Binary Sort Tree is empty, so it can not be traversal!!!" ); } } } class Node { int value; Node left; Node right; public Node (int value) { this .value = value; } public int leftHeight () { if (left == null ) { return 0 ; } return left.height(); } public int rightHeight () { if (right == null ) { return 0 ; } return right.height(); } public int height () { return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1 ; } public Node search (int value) { if (value == this .value) { return this ; } else if (value < this .value) { if (this .left == null ) { return null ; } return this .left.search(value); } else { if (this .right == null ) { return null ; } return this .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 (value < this .value && this .left != null ) { return this .left.searchParent(value); } else if (value >= this .value && this .right != null ) { return this .right.searchParent(value); } else { return null ; } } } 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); } } } @Override public String toString () { return "Node{" + "value=" + value + '}' ; } public void infixOrder () { if (this .left != null ) { this .left.infixOrder(); } System.out.println(this ); if (this .right != null ) { this .right.infixOrder(); } } }
左旋转 对二叉排序树进行左旋转,即变成了平衡二叉树。 由上面代码发现,左右两颗子树的高度差的绝对值超过了 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 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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 public class AVLTreeTest { public static void main (String[] args) { int [] arr = {4 , 3 , 6 , 5 , 7 , 8 }; AVLTree avlTree = new AVLTree(); for (int i = 0 ; i < arr.length; i++) { avlTree.add(new Node(arr[i])); } avlTree.infixOrder(); Node root = avlTree.getRoot(); System.out.println("树的高度 = " + root.height()); System.out.println("树的左子树高度 = " + root.leftHeight()); System.out.println("树的右子树高度 = " + root.rightHeight()); } } class AVLTree { private Node root; public Node getRoot () { return this .root; } public Node search (int value) { if (root == null ) { return null ; } else { return root.search(value); } } public Node searchParent (int value) { if (root == null ) { return null ; } else { return root.searchParent(value); } } public int delRightTreeMin (Node node) { Node temp = node; while (temp.left != null ) { temp = temp.left; } delNode(temp.value); return temp.value; } public void delNode (int value) { if (root == null ) { return ; } else { Node targetNode = search(value); if (targetNode == null ) { return ; } if (root.left == null && root.right == null ) { root = null ; return ; } Node parent = searchParent(value); if (targetNode.left == null && targetNode.right == null ) { if (parent.left != null && parent.left.value == value) { parent.left = null ; } else if (parent.right != null && parent.right.value == value) { parent.right = null ; } } else if (targetNode.left != null && targetNode.right != null ) { int minVal = delRightTreeMin(targetNode.right); targetNode.value = minVal; } else { if (targetNode.left != null ) { if (parent != null ) { if (parent.left.value == value) { parent.left = targetNode.left; } else { parent.right = targetNode.left; } } else { root = targetNode.left; } } else { if (parent != null ) { if (parent.left.value == value) { parent.left = targetNode.right; } else { parent.right = targetNode.right; } } else { root = targetNode.right; } } } } } public void add (Node node) { if (root == null ) { root = node; } else { root.add(node); } } public void infixOrder () { if (root != null ) { root.infixOrder(); } else { System.out.println("The Binary Sort Tree is empty, so it can not be traversal!!!" ); } } } class Node { int value; Node left; Node right; public Node (int value) { this .value = value; } public void leftRotate () { Node newNdoe = new Node(value); newNdoe.left = left; newNdoe.right = right.left; value = right.value; right = right.right; left = newNdoe; } public int leftHeight () { if (left == null ) { return 0 ; } return left.height(); } public int rightHeight () { if (right == null ) { return 0 ; } return right.height(); } public int height () { return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1 ; } public Node search (int value) { if (value == this .value) { return this ; } else if (value < this .value) { if (this .left == null ) { return null ; } return this .left.search(value); } else { if (this .right == null ) { return null ; } return this .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 (value < this .value && this .left != null ) { return this .left.searchParent(value); } else if (value >= this .value && this .right != null ) { return this .right.searchParent(value); } else { return null ; } } } 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 (rightHeight() - leftHeight() > 1 ) { leftRotate(); } } @Override public String toString () { return "Node{" + "value=" + value + '}' ; } public void infixOrder () { if (this .left != null ) { this .left.infixOrder(); } System.out.println(this ); if (this .right != null ) { this .right.infixOrder(); } } }
右旋转 对二叉排序树进行右旋转,即变成了平衡二叉树。 由上面代码发现,左右两颗子树的高度差的绝对值超过了 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 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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 public class AVLTreeTest { public static void main (String[] args) { int [] arr = {10 , 12 , 8 , 9 , 7 , 6 }; AVLTree avlTree = new AVLTree(); for (int i = 0 ; i < arr.length; i++) { avlTree.add(new Node(arr[i])); } avlTree.infixOrder(); Node root = avlTree.getRoot(); System.out.println("树的高度 = " + root.height()); System.out.println("树的左子树高度 = " + root.leftHeight()); System.out.println("树的右子树高度 = " + root.rightHeight()); System.out.println("当前根节点 = " + avlTree.getRoot()); } } class AVLTree { private Node root; public Node getRoot () { return this .root; } public Node search (int value) { if (root == null ) { return null ; } else { return root.search(value); } } public Node searchParent (int value) { if (root == null ) { return null ; } else { return root.searchParent(value); } } public int delRightTreeMin (Node node) { Node temp = node; while (temp.left != null ) { temp = temp.left; } delNode(temp.value); return temp.value; } public void delNode (int value) { if (root == null ) { return ; } else { Node targetNode = search(value); if (targetNode == null ) { return ; } if (root.left == null && root.right == null ) { root = null ; return ; } Node parent = searchParent(value); if (targetNode.left == null && targetNode.right == null ) { if (parent.left != null && parent.left.value == value) { parent.left = null ; } else if (parent.right != null && parent.right.value == value) { parent.right = null ; } } else if (targetNode.left != null && targetNode.right != null ) { int minVal = delRightTreeMin(targetNode.right); targetNode.value = minVal; } else { if (targetNode.left != null ) { if (parent != null ) { if (parent.left.value == value) { parent.left = targetNode.left; } else { parent.right = targetNode.left; } } else { root = targetNode.left; } } else { if (parent != null ) { if (parent.left.value == value) { parent.left = targetNode.right; } else { parent.right = targetNode.right; } } else { root = targetNode.right; } } } } } public void add (Node node) { if (root == null ) { root = node; } else { root.add(node); } } public void infixOrder () { if (root != null ) { root.infixOrder(); } else { System.out.println("The Binary Sort Tree is empty, so it can not be traversal!!!" ); } } } class Node { int value; Node left; Node right; public Node (int value) { this .value = value; } public void rightRotate () { Node newNdoe = new Node(value); newNdoe.right = right; newNdoe.left = left.right; value = left.value; left = left.left; right = newNdoe; } public void leftRotate () { Node newNdoe = new Node(value); newNdoe.left = left; newNdoe.right = right.left; value = right.value; right = right.right; left = newNdoe; } public int leftHeight () { if (left == null ) { return 0 ; } return left.height(); } public int rightHeight () { if (right == null ) { return 0 ; } return right.height(); } public int height () { return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1 ; } public Node search (int value) { if (value == this .value) { return this ; } else if (value < this .value) { if (this .left == null ) { return null ; } return this .left.search(value); } else { if (this .right == null ) { return null ; } return this .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 (value < this .value && this .left != null ) { return this .left.searchParent(value); } else if (value >= this .value && this .right != null ) { return this .right.searchParent(value); } else { return null ; } } } 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 (rightHeight() - leftHeight() > 1 ) { leftRotate(); } if (leftHeight() - rightHeight() > 1 ) { rightRotate(); } } @Override public String toString () { return "Node{" + "value=" + value + '}' ; } public void infixOrder () { if (this .left != null ) { this .left.infixOrder(); } System.out.println(this ); if (this .right != null ) { this .right.infixOrder(); } } }
双旋转 双旋转
主要是 为了解决左旋转和右旋转无法解决的问题。相关问题以及双旋转的思路分析 如下图:
双旋转 的代码实现如下:
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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 public class AVLTreeTest { public static void main (String[] args) { int [] arr = {10 , 11 , 7 , 6 , 8 , 9 }; AVLTree avlTree = new AVLTree(); for (int i = 0 ; i < arr.length; i++) { avlTree.add(new Node(arr[i])); } avlTree.infixOrder(); Node root = avlTree.getRoot(); System.out.println("树的高度 = " + root.height()); System.out.println("树的左子树高度 = " + root.leftHeight()); System.out.println("树的右子树高度 = " + root.rightHeight()); System.out.println("当前根节点 = " + avlTree.getRoot()); System.out.println("当前根节点的右子树的 …… " + avlTree.getRoot().right.right.left); } } class AVLTree { private Node root; public Node getRoot () { return this .root; } public Node search (int value) { if (root == null ) { return null ; } else { return root.search(value); } } public Node searchParent (int value) { if (root == null ) { return null ; } else { return root.searchParent(value); } } public int delRightTreeMin (Node node) { Node temp = node; while (temp.left != null ) { temp = temp.left; } delNode(temp.value); return temp.value; } public void delNode (int value) { if (root == null ) { return ; } else { Node targetNode = search(value); if (targetNode == null ) { return ; } if (root.left == null && root.right == null ) { root = null ; return ; } Node parent = searchParent(value); if (targetNode.left == null && targetNode.right == null ) { if (parent.left != null && parent.left.value == value) { parent.left = null ; } else if (parent.right != null && parent.right.value == value) { parent.right = null ; } } else if (targetNode.left != null && targetNode.right != null ) { int minVal = delRightTreeMin(targetNode.right); targetNode.value = minVal; } else { if (targetNode.left != null ) { if (parent != null ) { if (parent.left.value == value) { parent.left = targetNode.left; } else { parent.right = targetNode.left; } } else { root = targetNode.left; } } else { if (parent != null ) { if (parent.left.value == value) { parent.left = targetNode.right; } else { parent.right = targetNode.right; } } else { root = targetNode.right; } } } } } public void add (Node node) { if (root == null ) { root = node; } else { root.add(node); } } public void infixOrder () { if (root != null ) { root.infixOrder(); } else { System.out.println("The Binary Sort Tree is empty, so it can not be traversal!!!" ); } } } class Node { int value; Node left; Node right; public Node (int value) { this .value = value; } public void rightRotate () { Node newNdoe = new Node(value); newNdoe.right = right; newNdoe.left = left.right; value = left.value; left = left.left; right = newNdoe; } public void leftRotate () { Node newNdoe = new Node(value); newNdoe.left = left; newNdoe.right = right.left; value = right.value; right = right.right; left = newNdoe; } public int leftHeight () { if (left == null ) { return 0 ; } return left.height(); } public int rightHeight () { if (right == null ) { return 0 ; } return right.height(); } public int height () { return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1 ; } public Node search (int value) { if (value == this .value) { return this ; } else if (value < this .value) { if (this .left == null ) { return null ; } return this .left.search(value); } else { if (this .right == null ) { return null ; } return this .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 (value < this .value && this .left != null ) { return this .left.searchParent(value); } else if (value >= this .value && this .right != null ) { return this .right.searchParent(value); } else { return null ; } } } 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 (rightHeight() - leftHeight() > 1 ) { if (right != null && right.leftHeight() > right.rightHeight()) { right.rightRotate(); leftRotate(); } else { leftRotate(); } return ; } if (leftHeight() - rightHeight() > 1 ) { if (left != null && left.rightHeight() > left.leftHeight()) { left.leftRotate(); rightRotate(); } else { rightRotate(); } } } @Override public String toString () { return "Node{" + "value=" + value + '}' ; } public void infixOrder () { if (this .left != null ) { this .left.infixOrder(); } System.out.println(this ); if (this .right != null ) { this .right.infixOrder(); } } }
多路查找树
TIPS:
此部分的内容比较少用,且难度大。 所以这里只是简单的做一些概念了解,需要深入的同学请自行查阅资料!!!
二叉树和 B 树
2-3 树和 2-3-4 树
B 树、B+ 树和 B* 树
图的知识
为什么会有图这种数据结构?
原因:当我们需要表示多对多关系时,就要用到图这种数据结构。
图的举例说明 图是一种数据结构,其中结点可以具有零个或多个相邻元素。两个结点之间的连接称为 边
。 结点也可以称为 顶点
。如图:
图的常用概念 在学习图的过程中,理解常用概念是非常必要的,如下图:
图的表示方式
图的表示方式有两种:
1、二维数组表示(邻接矩阵)
2、链表表示(邻接表)
邻接矩阵 邻接矩阵是表示图形中顶点之间相邻关系的矩阵,对于 n 个顶点的图而言,矩阵是的 row 和 col 表示的是 1….n 个点。图与邻接矩阵的关系以及解释如下:
邻接表 邻接矩阵需要为每个顶点都分配 n 个边的空间,其实有很多边都是不存在,会造成空间的一定损失。邻接表的实现只关心存在的边,不关心不存在的边。因此没有空间浪费,邻接表由数组 + 链表组成,如下图:
图的入门案例 要求: 代码实现下面的图结构:
代码实现如下:
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 public class Main { public static void main (String[] args) { int nodeNum = 5 ; String[] str = {"A" , "B" , "C" , "D" , "E" }; Graph graph = new Graph(nodeNum); for (String vertex : str){ graph.insertVertex(vertex); } graph.insertEdge(0 , 1 , 1 ); graph.insertEdge(0 , 2 , 1 ); graph.insertEdge(1 , 2 , 1 ); graph.insertEdge(1 , 3 , 1 ); graph.insertEdge(1 , 4 , 1 ); graph.showGraph(); } } class Graph { private ArrayList<String> vertexList; private int [][] edges; private int numOfEdges; private boolean [] isVisited; public Graph (int n) { edges = new int [n][n]; vertexList = new ArrayList<String>(); numOfEdges = 0 ; } public void insertVertex (String vertex) { vertexList.add(vertex); } public void insertEdge (int v1, int v2, int weight) { edges[v1][v2] = weight; edges[v2][v1] = weight; numOfEdges++; } public int getNumOfVertex () { return vertexList.size(); } public void showGraph () { for (int [] link : edges) { System.out.println(Arrays.toString(link)); } } public int getNumOfEdges () { return numOfEdges; } public String getValueByIndex (int i) { return vertexList.get(i); } public int getWeight (int v1, int v2) { return edges[v1][v2]; } public int getFirstNeighbor (int index) { for (int i = 0 ; i < vertexList.size(); i++) { if (edges[index][i] > 0 ) { return i; } } return -1 ; } public int getNextNeighbor (int v1, int v2) { for (int i = v2 + 1 ; i < vertexList.size(); i++) { if (edges[v1][v2] > 0 ) { return i; } } return -1 ; } }
图的遍历
图的遍历:
所谓图的遍历,即是对结点的访问。一个图有那么多个结点,如何遍历这些结点,需要特定策略,一般有以下两种访问策略:
1、深度优先遍历
2、广度优先遍历
深度优先遍历(DFS) 深度优先遍历 ,从初始访问结点出发,初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点, 可以这样理解:每次都在访问完当前结点后首先访问当前结点的第一个邻接结点。这样的访问策略是优先往纵向挖掘深入,而不是对一个结点的所有邻接结点进行横向访问。显然,深度优先搜索是一个递归的过程。
深度优先遍历算法步骤:
1、访问初始结点v,并标记结点 v 为已访问。
2、查找结点 v 的第一个邻接结点 w 。
3、若 w 存在,则执行 4 ,如果 w 不存在,则回到第 1 步,将从 v 的下一个结点继续。
4、若 w 未被访问,对 w 进行深度优先遍历递归(即把w当做另一个 v ,然后进行步骤 123)。
5、查找结点 v 的 w 邻接结点的下一个邻接结点,转到步骤3。
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 public class Graph { private ArrayList<String> vertexList; private int [][] edges; private int numOfEdges; private boolean [] isVisited; public static void main (String[] args) { String[] str = {"1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" }; Graph graph = new Graph(8 ); for (String vertex : str) { graph.insertVertex(vertex); } graph.insertEdge(0 , 1 ); graph.insertEdge(0 , 2 ); graph.insertEdge(1 , 3 ); graph.insertEdge(1 , 4 ); graph.insertEdge(3 , 7 ); graph.insertEdge(4 , 7 ); graph.insertEdge(2 , 5 ); graph.insertEdge(2 , 6 ); graph.insertEdge(5 , 6 ); graph.showGraph(); System.out.println("\n深度优先遍历顺序如下:" ); graph.dfs(); } public Graph (int n) { edges = new int [n][n]; vertexList = new ArrayList<String>(); numOfEdges = 0 ; } public void insertVertex (String vertex) { vertexList.add(vertex); } public void insertEdge (int v1, int v2) { edges[v1][v2] = 1 ; edges[v2][v1] = 1 ; numOfEdges++; } public int getNumOfVertex () { return vertexList.size(); } public void showGraph () { for (int [] link : edges) { System.out.println(Arrays.toString(link)); } } public int getNumOfEdges () { return numOfEdges; } public String getValueByIndex (int i) { return vertexList.get(i); } public int getWeight (int v1, int v2) { return edges[v1][v2]; } public int getFirstNeighbor (int index) { for (int i = 0 ; i < vertexList.size(); i++) { if (edges[index][i] > 0 ) { return i; } } return -1 ; } public int getNextNeighbor (int v1, int v2) { for (int i = v2 + 1 ; i < vertexList.size(); i++) { if (edges[v1][i] > 0 ) { return i; } } return -1 ; } private void dfs (boolean [] isVisited, int i) { System.out.print(getValueByIndex(i) + "-->" ); isVisited[i] = true ; int w = getFirstNeighbor(i); while (w != -1 ) { if (!isVisited[w]) { dfs(isVisited, w); } w = getNextNeighbor(i, w); } } public void dfs () { isVisited = new boolean [vertexList.size()]; for (int i = 0 ; i < getNumOfVertex(); i++) { if (!isVisited[i]) { dfs(isVisited, i); } } } }
广度优先遍历(BFS) 图的广度优先搜索(Broad First Search) ,类似于一个分层搜索的过程,广度优先遍历需要使用一个队列以保持访问过的结点的顺序,以便按这个顺序来访问这些结点的邻接结点
具体实现步骤:
1、访问初始结点v并标记结点v为已访问。
2、结点v入队列
3、当队列非空时,继续执行,否则算法结束。
4、出队列,取得队头结点u。
6、查找结点u的第一个邻接结点w。
6、若结点u的邻接结点w不存在,则转到步骤3;否则循环执行以下三个步骤:
6.1 若结点w尚未被访问,则访问结点w并标记为已访问。
6.2 结点w入队列
6.3 查找结点u的继w邻接结点后的下一个邻接结点w,转到步骤6。
广度优先遍历代码实现:
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 194 195 196 197 198 199 public class Main { public static void main (String[] args) { int nodeNum = 5 ; String[] str = {"A" , "B" , "C" , "D" , "E" }; Graph graph = new Graph(nodeNum); for (String vertex : str) { graph.insertVertex(vertex); } graph.insertEdge(0 , 1 , 1 ); graph.insertEdge(0 , 2 , 1 ); graph.insertEdge(1 , 2 , 1 ); graph.insertEdge(1 , 3 , 1 ); graph.insertEdge(1 , 4 , 1 ); graph.showGraph(); System.out.println("\n深度优先遍历顺序如下:" ); graph.dfs(); System.out.println("\n广度优先遍历顺序如下:" ); graph.bfs(); } } class Graph { private ArrayList<String> vertexList; private int [][] edges; private int numOfEdges; private boolean [] isVisited; public Graph (int n) { edges = new int [n][n]; vertexList = new ArrayList<String>(); numOfEdges = 0 ; } public void insertVertex (String vertex) { vertexList.add(vertex); } public void insertEdge (int v1, int v2, int weight) { edges[v1][v2] = weight; edges[v2][v1] = weight; numOfEdges++; } public int getNumOfVertex () { return vertexList.size(); } public void showGraph () { for (int [] link : edges) { System.out.println(Arrays.toString(link)); } } public int getNumOfEdges () { return numOfEdges; } public String getValueByIndex (int i) { return vertexList.get(i); } public int getWeight (int v1, int v2) { return edges[v1][v2]; } public int getFirstNeighbor (int index) { for (int i = 0 ; i < vertexList.size(); i++) { if (edges[index][i] > 0 ) { return i; } } return -1 ; } public int getNextNeighbor (int v1, int v2) { for (int i = v2 + 1 ; i < vertexList.size(); i++) { if (edges[v1][v2] > 0 ) { return i; } } return -1 ; } private void dfs (boolean [] isVisited, int i) { if (i == vertexList.size() - 1 ) { System.out.println(getValueByIndex(i)); } else { System.out.print(getValueByIndex(i) + "-->" ); } isVisited[i] = true ; int w = getFirstNeighbor(i); while (w != -1 ) { if (!isVisited[w]) { dfs(isVisited, w); } w = getNextNeighbor(i, w); } } public void dfs () { isVisited = new boolean [vertexList.size()]; for (int i = 0 ; i < getNumOfVertex(); i++) { if (!isVisited[i]) { dfs(isVisited, i); } } } private void bfs (boolean [] isVisited, int i) { int u; int w; LinkedList queue = new LinkedList(); if (i == vertexList.size() - 1 ) { System.out.println(getValueByIndex(i)); } else { System.out.print(getValueByIndex(i) + "-->" ); } isVisited[i] = true ; queue.addLast(i); while (!queue.isEmpty()) { u = (Integer) queue.removeFirst(); w = getFirstNeighbor(u); while (w != -1 ) { if (!isVisited[w]) { if (w == vertexList.size() - 1 ) { System.out.println(getValueByIndex(w)); } else { System.out.print(getValueByIndex(w) + "-->" ); } isVisited[w] = true ; queue.addLast(w); } w = getNextNeighbor(u, w); } } } public void bfs () { isVisited = new boolean [vertexList.size()]; for (int i = 0 ; i < getNumOfVertex(); i++) { if (!isVisited[i]) { bfs(isVisited, 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 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 194 195 196 197 198 199 200 201 202 203 public class Main { public static void main (String[] args) { int nodeNum = 8 ; String[] str = {"1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" };; Graph graph = new Graph(nodeNum); for (String vertex : str) { graph.insertVertex(vertex); } graph.insertEdge(0 , 1 , 1 ); graph.insertEdge(0 , 2 , 1 ); graph.insertEdge(1 , 3 , 1 ); graph.insertEdge(1 , 4 , 1 ); graph.insertEdge(3 , 7 , 1 ); graph.insertEdge(4 , 7 , 1 ); graph.insertEdge(2 , 5 , 1 ); graph.insertEdge(2 , 6 , 1 ); graph.insertEdge(5 , 6 , 1 ); graph.showGraph(); System.out.println("\n深度优先遍历顺序如下:" ); graph.dfs(); System.out.println("\n广度优先遍历顺序如下:" ); graph.bfs(); } } class Graph { private ArrayList<String> vertexList; private int [][] edges; private int numOfEdges; private boolean [] isVisited; public Graph (int n) { edges = new int [n][n]; vertexList = new ArrayList<String>(); numOfEdges = 0 ; } public void insertVertex (String vertex) { vertexList.add(vertex); } public void insertEdge (int v1, int v2, int weight) { edges[v1][v2] = weight; edges[v2][v1] = weight; numOfEdges++; } public int getNumOfVertex () { return vertexList.size(); } public void showGraph () { for (int [] link : edges) { System.out.println(Arrays.toString(link)); } } public int getNumOfEdges () { return numOfEdges; } public String getValueByIndex (int i) { return vertexList.get(i); } public int getWeight (int v1, int v2) { return edges[v1][v2]; } public int getFirstNeighbor (int index) { for (int i = 0 ; i < vertexList.size(); i++) { if (edges[index][i] > 0 ) { return i; } } return -1 ; } public int getNextNeighbor (int v1, int v2) { for (int i = v2 + 1 ; i < vertexList.size(); i++) { if (edges[v1][v2] > 0 ) { return i; } } return -1 ; } private void dfs (boolean [] isVisited, int i) { if (i == vertexList.size() - 1 ) { System.out.println(getValueByIndex(i)); } else { System.out.print(getValueByIndex(i) + "-->" ); } isVisited[i] = true ; int w = getFirstNeighbor(i); while (w != -1 ) { if (!isVisited[w]) { dfs(isVisited, w); } w = getNextNeighbor(i, w); } } public void dfs () { isVisited = new boolean [vertexList.size()]; for (int i = 0 ; i < getNumOfVertex(); i++) { if (!isVisited[i]) { dfs(isVisited, i); } } } private void bfs (boolean [] isVisited, int i) { int u; int w; LinkedList queue = new LinkedList(); if (i == vertexList.size() - 1 ) { System.out.println(getValueByIndex(i)); } else { System.out.print(getValueByIndex(i) + "-->" ); } isVisited[i] = true ; queue.addLast(i); while (!queue.isEmpty()) { u = (Integer) queue.removeFirst(); w = getFirstNeighbor(u); while (w != -1 ) { if (!isVisited[w]) { if (w == vertexList.size() - 1 ) { System.out.println(getValueByIndex(w)); } else { System.out.print(getValueByIndex(w) + "-->" ); } isVisited[w] = true ; queue.addLast(w); } w = getNextNeighbor(u, w); } } } public void bfs () { isVisited = new boolean [vertexList.size()]; for (int i = 0 ; i < getNumOfVertex(); i++) { if (!isVisited[i]) { bfs(isVisited, 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 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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 数据结构:逻辑结构和物理结构(数据在计算机内部的物理存储方式) 数据元素存储形式:顺序存储结构和链式存储结构(银行排队叫号系统) 逻辑结构:集合结构、线性结构、树形结构(金字塔关系)、图形结构 了解:六度空间理论 了解算法:就是解决问题的方法。例如:求从1加到100的和。使用for循环和等差公式,对计算机来说都没有什么差别,但加到10000000就差别大了,这就是算法。 算法5个特性:零个或多个输入、至少一个或多个输出、有穷性、确定性和可行性。 算法设计要求:正确性、可读性、健壮性、时间效率高和存储量低。 时间复杂度(渐近时间复杂度):使用大O体现算法时间复杂度,成为大O计法。 线性阶:非嵌套循环涉及线性阶,对应次数成直线增长。 平方阶:两个嵌套循环涉及平方阶。 对数阶:例如下面的程序:2的x次方=n,求解之后x=log(2)n,所以时间复杂度为O(logn) 还有常数阶,立方阶,指数阶。nlogn阶。 int i = 1, n = 100; while(i < n) { i = i * 2; } 最坏情况: 平均情况:平均运行时间就是期望运行时间。 空间复杂度:写代码时,可以用空间换取时间。闰年算法的例子。 线性表: 存和读的情况:时间复杂度为O(1) 插入和删除情况:时间复杂度为O(n) 单链表: 结点:数据域和指针域合在一起叫做结点 数据域:存放数据的地方 指针域:存放下一个地址的地方 第一个结点叫做头结点(头指针)头结点一般不存储任何东西,头指针指向头结点,最后一个结点指向NULL 下一次看线性表第6集 ====================================== 认识时间复杂度,用big O表示 二分搜索,时间复杂度O(log2N) 外排(谁小谁移动) 题目:给定一个M个数的数组a和N个数的数组B,数组a乱序,数组b顺序,求两个数组共有多少个相同的数的复杂度? 第一种:嵌套for循环,复杂度为O(M*N) 第二种:对数组b(数组b是顺序的)使用二分查找,时间复杂度O(M*log2N) 第三种:使用外排,先对数组a进行排序,然后使用外排,就是将两个数组的索引指向0,指向数字谁小谁就往下移动一个位置,直到结束。 选择排序: 第一次排序把最小的放在第一位,第二次排序把第二小的数字放在第二位,以此类推,直至结束。 这种排序和数据状况没有关系,即便是一个排好的数组,它的时间复杂度仍然不变。 冒泡排序: 在一个数组中,相邻位置的数进行比较。进行完第一轮排序,最大的数字会在最后一个位置。那么下一轮排序就不用比较最后一个数字了。 这种排序和数据状况没有关系,即便是一个排好的数组,它的时间复杂度仍然不变。 插入排序: 就像打扑克牌一样,一副排好序的牌,然后你摸了一张牌,就要给这张牌找位置,这就是插入排序。 插入排序和数据状况有关,例如:数组元素1,2,3,4,5,那么插入排序复杂度为O(N),如果是5,4,3,2,1,那么复杂度为O(N2). 一般情况下,都是按照最坏情况作为一个算法的复杂度。 最好情况: 平均情况: 最坏情况: 以上三种情况在插入排序可见,自己百度以下平均情况。 对数器【很重要的】:方法在排序代码里有。先要有随机数组产生器,然后需要绝对正确的方法,接着进行大样本的测试。 堆的结构准备模板,排序、二叉树、数组也要准备对数器模板。 冒泡和选择公司已经不使用了,只具有参考和教学意义。 递归算法:1:38:26 递归如何求时间复杂度?1:51:49 时间复杂度求解公式1:54:30 归并排序: master公式 复杂度为O(N*log2N) 计算机网络看视频从第一章开始看,同时参观CSDN别人的博客。 =============================== 韩顺平老师数据结构: =============================== KMP算法: 汉诺塔问题:使用分治算法 八皇后问题:使用回溯算法 骑士周游问题:DFS+贪心算法 场合不同,所使用的算法不一样 五子棋程序 约瑟夫问题【单向环形链表】 稀疏数组和队列 队列的应用:队列是个有序列表,可以用数组或者链表实现。特点:先进先出 队列加数据在尾部加入,且rear+1,取数据在头部取,且front+1。 queue包里面代码:数组实现队列和链表实现队列。 数组模拟成环形队列。 栈的应用:如子弹的弹夹,最先压入的子弹最后打出。 线性表:自己补充 单链表知识:看完写博客 双向链表: (环形链表)约瑟夫环: 排序算法: 内容在 PPT 上 已看:50 51 冒泡排序: 选择排序: 插入排序: 希尔排序: 快速排序: 归并排序: 基数排序: 桶排序: 堆排序: 计数排序: 查找算法: 顺序(线性)查找: 二分查找/折半查找: 插值查找: 非常的牛逼 斐波那契查找(黄金分割查找): 哈希表: 二叉树: - 各种二叉树术语 - 三种遍历方式 - 二叉树的查找 - 二叉树的删除 - 顺序存储二叉树 - 线索化二叉树 - 堆排序:先变成大顶堆,然后排序 赫夫曼树: wpl最小的就是赫夫曼树,赫夫曼树也是二叉树 赫夫曼编码:不要前缀编码,就是不要出现二义性 赫夫曼压缩 赫夫曼解压 二叉排序树: - 创建 - 遍历 - 删除 平衡二叉树: - 左旋转 - 右旋转 - 双旋转 多叉树: B树 - 2-3树 - 234树 B+树 B*树 多路查找树 图: 图的基本术语 图的邻接矩阵 图的邻接表 图的遍历方式: - 深度优先遍历(DFS) - 广度优先遍历(BFS) 想要理解清楚 DFS 和 BFS 的区别,就要以图的邻接矩阵为例子,更好理解一点。 程序员常用的 10 中算法: - 二分查找算法(非递归) - 分治算法(汉诺塔问题)【使用了递归算法】 - 动态规划算法(背包问题) - KMP 算法(字符串匹配问题) - 暴力匹配算法 - 贪心算法 - 普利姆算法(prim算法)(修路问题)(最小生成树问题) - 克鲁斯卡尔算法(公交站问题) - 迪杰斯特拉算法(最短路径问题) - 弗洛伊德算法 - 马踏棋盘算法(骑士周游问题) 卖油翁和老黄牛的故事: 在通往成功的路上,我们必须坚持,不要中途放弃,自毁前程,而要勇往直前,坚持不懈,最终会抵达理想的彼岸。既然选择了远方,便只顾风雨兼程。