代码仓库的地址:https://gitee.com/JasonsGong/DataStructures
一.经典算法问题 字符串匹配 KMP算法
汉诺塔问题 分治算法
八皇后问题 回溯算法
马踏棋盘问题 图的深度优化遍历算法(DFS)和 贪心算法优化
二.数据结构与算法的概述 2.1 数据结构与算法的关系 (1)数据(data)结构(structure)是一门研究组织数据方式的学科,有了编程语言也就有了数据结构,学好了数据结构可以编写出更加漂亮,更加有效率的代码。
(2)程序=数据结构+算法
(3)数据结构是算法的基础
2.2解决实际的问题 五子棋程序 稀疏数组(压缩存档) 二维数组->转化成稀疏数组->存档 读档反之
约瑟夫问题(丢手帕问题) 单向环形列表
修路问题 求最小生成树 + 普利姆算法
最短路径问题 图+弗洛伊德算法
2.3 数据结构 线性结构:
线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系
线性结构有两种不同的存储结构,即顺序存储结构和链式存储结构。顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的
链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息
线性结构常见的有:数组、队列、链表和栈
非线性结构:
二维数组,多维数组,广义表,树结构,图结构
三.稀疏数组和队列 3.1稀疏数组 3.1.1 基本的介绍 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法是:
1)记录数组一共有几行几列,有多少个不同的值
2)把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模
3.1.2使用的场景 五子棋程序的存档和退出功能的实现
3.1.3图解 第一行记录的是原始的数组有几行几列有几个非零的值 例如下面的数组是一个6行7列有8个非零值的数组
3.1.5实现的思路
3.1.5代码实现 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 package com.atguigu.sparsearray;public class SparseArray { public static void main (String[] args) { int [][] chessArr1 = new int [11 ][11 ]; chessArr1[1 ][2 ] = 1 ; chessArr1[2 ][3 ] = 2 ; chessArr1[4 ][5 ] = 1 ; System.out.println("原始的二维数组" ); for (int [] row : chessArr1) { for (int num : row) { System.out.print(num + " " ); } System.out.println(); } int sum = 0 ; for (int [] row : chessArr1) { for (int num : row) { if (num != 0 ) { sum++; } } } System.out.println("非零元素的个数:" + sum); int [][] sparseArr2 = new int [sum + 1 ][3 ]; sparseArr2[0 ][0 ] = 11 ; sparseArr2[0 ][1 ] = 11 ; sparseArr2[0 ][2 ] = sum; int row = 1 ; for (int i = 0 ; i < chessArr1.length; i++) { for (int j = 0 ; j < chessArr1[i].length; j++) { if (chessArr1[i][j] != 0 ) { sparseArr2[row][0 ] = i; sparseArr2[row][1 ] = j; sparseArr2[row][2 ] = chessArr1[i][j]; row++; } } } System.out.println("得到的稀疏数组如下" ); for (int [] ints : sparseArr2) { for (int anInt : ints) { System.out.print(anInt + " " ); } System.out.println(); } int [][] sparseArr3 = new int [sparseArr2[0 ][0 ]][sparseArr2[0 ][1 ]]; for (int i = 1 ; i < sparseArr2.length; i++) { sparseArr3[sparseArr2[i][0 ]][sparseArr2[i][1 ]] = sparseArr2[i][2 ]; } System.out.println("稀疏数组还原成二维数组" ); for (int [] ints : sparseArr3) { for (int anInt : ints) { System.out.print(anInt+" " ); } System.out.println(); } } }
3.2队列 3.2.1基本的介绍 先进先出
队列是一个有序列表,可以通过数组或者链表实现。
遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入队列的数据要后取出。
3.2.2代码实现 使用数组模拟队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 package com.atguigu.queue;import java.util.Scanner;public class ArrayQueueDemo { public static void main (String[] args) { ArrayQueue queue = 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' : queue.showQueue(); break ; case 'a' : System.out.println("输出一个数" ); int value = scanner.nextInt(); queue.addQueue(value); break ; case 'g' : try { int res = queue.getQueue(); System.out.printf("取出的数据是%d\n" , res); } catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'h' : try { int res = queue.headQueue(); System.out.printf("队列头的数据是%d\n" , res); } catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'e' : scanner.close(); loop = false ; break ; default : break ; } } System.out.println("程序退出~~" ); } } 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 n) { if (isFull()) { System.out.println("队列满,不能加入数据~" ); return ; } rear++; arr[rear] = n; } public int getQueue () { if (isEmpty()) { throw new RuntimeException ("队列空,不能取数据" ); } front++; return arr[front]; } public void showQueue () { if (isEmpty()) { System.out.println("队列空的,没有数据~~" ); return ; } 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 + 1 ]; } }
3.2.3 数组模拟环形队列 环形队列的思路分析
环形队列满的条件:(rear + 1) % maxSize == front
环形队列空的条件:rear == front
环形队列中有效数据的个数: (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 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 package com.atguigu.queue;import java.util.Scanner;public class CircleArrayQueueDemo { public static void main (String[] args) { System.out.println("测试环形队列" ); CircleArray queue = new CircleArray (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' : queue.showQueue(); break ; case 'a' : System.out.println("输出一个数" ); int value = scanner.nextInt(); queue.addQueue(value); break ; case 'g' : try { int res = queue.getQueue(); System.out.printf("取出的数据是%d\n" , res); } catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'h' : try { int res = queue.headQueue(); System.out.printf("队列头的数据是%d\n" , res); } catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'e' : scanner.close(); loop = false ; break ; default : break ; } } System.out.println("程序退出~~" ); } } class CircleArray { private int maxSize; private int front; private int rear; private int [] arr; public CircleArray (int arrMaxSize) { maxSize = arrMaxSize; arr = new int [maxSize]; } public boolean isFull () { return (rear + 1 ) % maxSize == front; } public boolean isEmpty () { return rear == front; } public void addQueue (int n) { if (this .isFull()) { System.out.println("队列为满,不能添加数据!" ); return ; } arr[rear] = n; rear = (rear + 1 ) % maxSize; } public int getQueue () { if (this .isEmpty()) { System.out.println("队列为空,无法取出数据!" ); throw new RuntimeException ("队列空,不能取数据" ); } int result = arr[front]; front = (front + 1 ) % maxSize; return result; } public void showQueue () { if (this .isEmpty()) { System.out.println("队列为空!" ); return ; } int count = this .size(); for (int i = front; i < front + count; i++) { System.out.println("arr[" + i % maxSize + "]=" + arr[i % maxSize]); } } public int size () { return (rear + maxSize - front) % maxSize; } public int headQueue () { if (isEmpty()) { throw new RuntimeException ("队列空的,没有数据~~" ); } return arr[front]; } }
四.链表 4.1 链表(Linked List)介绍 在内存中不是连续存储的
链表的逻辑结构
4.2单链表的应用实例(CRUD) 使用带head头的单向链表实现 –水浒英雄排行榜管理 完成对英雄人物的增删改查操作
4.2.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 package com.atguigu.linkedlist;public class SingleLinkedListDemo { public static void main (String[] args) { SingleLinkedList singleLinkedList = new SingleLinkedList (); singleLinkedList.add(new HeroNode (1 , "宋江" , "及时雨" )); singleLinkedList.add(new HeroNode (2 , "卢俊义" , "玉麒麟" )); singleLinkedList.add(new HeroNode (3 , "吴用" , "智多星" )); singleLinkedList.add(new HeroNode (4 , "林冲" , "豹子头" )); singleLinkedList.list(); } } class SingleLinkedList { private HeroNode head = new HeroNode (0 , "" , "" ); public void add (HeroNode heroNode) { HeroNode temp = head; while (temp.next != null ) { temp = temp.next; } temp.next = heroNode; } public void list () { if (head.next == null ) { System.out.println("链表为空!" ); return ; } HeroNode temp = head; while (temp.next != null ) { System.out.println(temp.next); 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 + '\'' + '}' ; } }
4.2.2修改单链表中节点的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public void update (HeroNode newHeroNode) { if (head.next == null ) { System.out.println("链表为空,无法修改该节点!" ); return ; } HeroNode temp = head.next; boolean idFind = false ; while (true ) { if (temp == null ) { break ; } if (temp.no == newHeroNode.no) { temp.name = newHeroNode.name; temp.nickname = newHeroNode.nickname; idFind = true ; break ; } temp = temp.next; } System.out.println(idFind ? "修改成功" : "没有找到该节点的信息" ); }
4.2.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 public void delete (int no) { if (head.next == null ) { System.out.println("链表为空,无法删除!" ); return ; } HeroNode temp = head; boolean isDelete = false ; while (true ) { if (temp.next == null ) { break ; } if (temp.next.no == no) { temp.next = temp.next.next; isDelete = true ; break ; } temp = temp.next; } System.out.println(isDelete ? "删除成功" : "没有找到该节点的信息" ); }
4.2.4完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 package com.atguigu.linkedlist;public class SingleLinkedListDemo { public static void main (String[] args) { SingleLinkedList singleLinkedList = new SingleLinkedList (); singleLinkedList.add(new HeroNode (1 , "宋江" , "及时雨" )); singleLinkedList.add(new HeroNode (2 , "卢俊义" , "玉麒麟" )); singleLinkedList.add(new HeroNode (3 , "吴用" , "智多星" )); singleLinkedList.add(new HeroNode (4 , "林冲" , "豹子头" )); singleLinkedList.list(); singleLinkedList.update(new HeroNode (2 , "卢俊义" , "玉麒麟增强版" )); singleLinkedList.list(); singleLinkedList.delete(2 ); singleLinkedList.list(); } } class SingleLinkedList { private HeroNode head = new HeroNode (0 , "" , "" ); public void delete (int no) { if (head.next == null ) { System.out.println("链表为空,无法删除!" ); return ; } HeroNode temp = head; boolean isDelete = false ; while (true ) { if (temp.next == null ) { break ; } if (temp.next.no == no) { temp.next = temp.next.next; isDelete = true ; break ; } temp = temp.next; } System.out.println(isDelete ? "删除成功" : "没有找到该节点的信息" ); } public void update (HeroNode newHeroNode) { if (head.next == null ) { System.out.println("链表为空,无法修改该节点!" ); return ; } HeroNode temp = head.next; boolean idFind = false ; while (true ) { if (temp == null ) { break ; } if (temp.no == newHeroNode.no) { temp.name = newHeroNode.name; temp.nickname = newHeroNode.nickname; idFind = true ; break ; } temp = temp.next; } System.out.println(idFind ? "修改成功" : "没有找到该节点的信息" ); } public void add (HeroNode heroNode) { HeroNode temp = head; while (temp.next != null ) { temp = temp.next; } temp.next = heroNode; } public void list () { if (head.next == null ) { System.out.println("链表为空!" ); return ; } HeroNode temp = head; while (temp.next != null ) { System.out.println(temp.next); 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 + '\'' + '}' ; } }
4.2.5 单链表的面试题(新浪,百度,腾讯) 1.求单链表中有效节点的个数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public int getLength (HeroNode heroNode) { if (heroNode.next == null ){ return 0 ; } int length = 0 ; HeroNode temp = heroNode.next; while (temp != null ){ length++; temp = temp.next; } return length; }
2.查找单链表中的倒数第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 public HeroNode getHeroNodeByLastIndex (int index, HeroNode heroNode) { if (heroNode.next == null ) { return null ; } int length = this .getLength(heroNode); index = length - index; if (index < 0 || index > length) { System.out.println("所求的在链表中不存在" ); return null ; } int count = 0 ; HeroNode temp = heroNode.next; while (true ) { if (count == index) { return temp; } count++; temp = temp.next; } }
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 public void reverseHeroNode (HeroNode heroNode) { if (head.next == null || head.next.next == null ){ System.out.println("当前链表为空或者只有一个节点,无需反转" ); return ; } HeroNode cur = head.next; HeroNode next = null ; HeroNode reverseHeroNode = new HeroNode (0 , "" , "" ); while (cur != null ){ next = cur.next; cur.next = reverseHeroNode.next; reverseHeroNode.next = cur; cur = next; } head.next = reverseHeroNode.next; }
4.从尾到头打印单链表(百度面试题) 不改变链表本身的结构(不是通过链表的反转之后再打印的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public void reversePrint (HeroNode heroNode) { if (head.next == null ) { System.out.println("当前链表为空,无法逆序打印!" ); return ; } Stack<HeroNode> stack = new Stack <>(); HeroNode cur = heroNode.next; while (cur != null ) { stack.push(cur); cur = cur.next; } while (stack.size() > 0 ) { System.out.println(stack.pop()); } }
5.合并两个有序的单链表,合并之后的链表依然有序 以下代码有一些bug 后期修改
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 public static void mergeHeroNode (HeroNode oneHead, HeroNode twoHead ,HeroNode head) { if (oneHead.next == null || twoHead.next == null ) { System.out.println("其中有一个(两个)链表为空,无法合并" ); return ; } HeroNode oneCur = oneHead.next; HeroNode twoCur = twoHead.next; HeroNode oneNext = null ; HeroNode twoNext = null ; HeroNode finalHeroHead = new HeroNode (0 , "" , "" ); while (oneCur != null && twoCur != null ) { oneNext = oneCur.next; twoNext = twoCur.next; if (oneCur.no <= twoCur.no) { oneCur.next = finalHeroHead.next; finalHeroHead.next = oneCur; oneCur = oneNext; }else { twoCur.next = finalHeroHead.next; finalHeroHead.next = twoCur; twoCur = twoNext; } } head.next = finalHeroHead.next; }
全部代码 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 package com.atguigu.linkedlist;import java.util.Stack;public class SingleLinkedListDemo { public static void main (String[] args) { SingleLinkedList singleLinkedList = new SingleLinkedList (); SingleLinkedList singleLinkedList1 = new SingleLinkedList (); singleLinkedList1.add(new HeroNode (1 , "宋江" , "及时雨" )); singleLinkedList1.add(new HeroNode (3 , "卢俊义" , "玉麒麟" )); singleLinkedList1.add(new HeroNode (5 , "吴用" , "智多星" )); singleLinkedList1.add(new HeroNode (7 , "林冲" , "豹子头" )); SingleLinkedList singleLinkedList2 = new SingleLinkedList (); singleLinkedList2.add(new HeroNode (2 , "宋江" , "及时雨" )); singleLinkedList2.add(new HeroNode (4 , "卢俊义" , "玉麒麟" )); singleLinkedList2.add(new HeroNode (6 , "吴用" , "智多星" )); singleLinkedList2.add(new HeroNode (8 , "林冲" , "豹子头" )); mergeHeroNode(singleLinkedList1.getHead(),singleLinkedList2.getHead(),singleLinkedList.getHead()); singleLinkedList.list(); } public static void mergeHeroNode (HeroNode oneHead, HeroNode twoHead ,HeroNode head) { if (oneHead.next == null || twoHead.next == null ) { System.out.println("其中有一个(两个)链表为空,无法合并" ); return ; } HeroNode oneCur = oneHead.next; HeroNode twoCur = twoHead.next; HeroNode oneNext = null ; HeroNode twoNext = null ; HeroNode finalHeroHead = new HeroNode (0 , "" , "" ); while (oneCur != null && twoCur != null ) { oneNext = oneCur.next; twoNext = twoCur.next; if (oneCur.no <= twoCur.no) { oneCur.next = finalHeroHead.next; finalHeroHead.next = oneCur; oneCur = oneNext; }else { twoCur.next = finalHeroHead.next; finalHeroHead.next = twoCur; twoCur = twoNext; } } head.next = finalHeroHead.next; } } class SingleLinkedList { private HeroNode head = new HeroNode (0 , "" , "" ); public HeroNode getHead () { return head; } public void reversePrint (HeroNode heroNode) { if (heroNode.next == null ) { System.out.println("当前链表为空,无法逆序打印!" ); return ; } Stack<HeroNode> stack = new Stack <>(); HeroNode cur = heroNode.next; while (cur != null ) { stack.push(cur); cur = cur.next; } while (stack.size() > 0 ) { System.out.println(stack.pop()); } } public void reverseHeroNode (HeroNode heroNode) { if (heroNode.next == null || heroNode.next.next == null ) { System.out.println("当前链表为空或者只有一个节点,无需反转" ); return ; } HeroNode cur = heroNode.next; HeroNode next = null ; HeroNode reverseHeroNode = new HeroNode (0 , "" , "" ); while (cur != null ) { next = cur.next; cur.next = reverseHeroNode.next; reverseHeroNode.next = cur; cur = next; } heroNode.next = reverseHeroNode.next; } public HeroNode getHeroNodeByLastIndex (int index, HeroNode heroNode) { if (heroNode.next == null ) { return null ; } int length = this .getLength(heroNode); index = length - index; if (index < 0 || index > length) { System.out.println("所求的在链表中不存在" ); return null ; } int count = 0 ; HeroNode temp = heroNode.next; while (true ) { if (count == index) { return temp; } count++; temp = temp.next; } } public int getLength (HeroNode heroNode) { if (heroNode.next == null ) { return 0 ; } int length = 0 ; HeroNode temp = heroNode.next; while (temp != null ) { length++; temp = temp.next; } return length; } public void delete (int no) { if (head.next == null ) { System.out.println("链表为空,无法删除!" ); return ; } HeroNode temp = head; boolean isDelete = false ; while (true ) { if (temp.next == null ) { break ; } if (temp.next.no == no) { temp.next = temp.next.next; isDelete = true ; break ; } temp = temp.next; } System.out.println(isDelete ? "删除成功" : "没有找到该节点的信息" ); } public void update (HeroNode newHeroNode) { if (head.next == null ) { System.out.println("链表为空,无法修改该节点!" ); return ; } HeroNode temp = head.next; boolean idFind = false ; while (true ) { if (temp == null ) { break ; } if (temp.no == newHeroNode.no) { temp.name = newHeroNode.name; temp.nickname = newHeroNode.nickname; idFind = true ; break ; } temp = temp.next; } System.out.println(idFind ? "修改成功" : "没有找到该节点的信息" ); } public void add (HeroNode heroNode) { HeroNode temp = head; while (temp.next != null ) { temp = temp.next; } temp.next = heroNode; } public void list () { if (head.next == null ) { System.out.println("链表为空!" ); return ; } HeroNode temp = head; while (temp.next != null ) { System.out.println(temp.next); 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 + '\'' + '}' ; } }
4.3 双向链表 双向的链表的CRUD操作于单向链表的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 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 package com.atguigu.linkedlist;public class DoubleLinkedListDemo { public static void main (String[] args) { DoubleLinkedList doubleLinkedList = new DoubleLinkedList (); doubleLinkedList.add(new HeroNode2 (1 , "宋江" , "及时雨" )); doubleLinkedList.add(new HeroNode2 (2 , "卢俊义" , "玉麒麟" )); doubleLinkedList.add(new HeroNode2 (3 , "吴用" , "智多星" )); doubleLinkedList.add(new HeroNode2 (4 , "林冲" , "豹子头" )); doubleLinkedList.list(); doubleLinkedList.delete(2 ); doubleLinkedList.list(); doubleLinkedList.update(new HeroNode2 (2 , "卢俊义修改版" , "玉麒麟" )); doubleLinkedList.list(); System.out.println("--------------" ); doubleLinkedList.orderAdd(new HeroNode2 (3 , "小卢" , "玉麒麟" )); doubleLinkedList.list(); } } class DoubleLinkedList { private HeroNode2 head = new HeroNode2 (0 , "" , "" ); public HeroNode2 getHead () { return head; } public void orderAdd (HeroNode2 heroNode) { HeroNode2 temp = head; boolean isSuccess = false ; while (temp.next != null ) { if (temp.next.no >= heroNode.no) { heroNode.next = temp.next; temp.next.pre = heroNode; temp.next = heroNode; heroNode.pre = temp; isSuccess = true ; break ; } temp = temp.next; } if (!isSuccess) { this .add(heroNode); } } public void delete (int no) { if (head.next == null ) { System.out.println("链表为空,无法删除!" ); return ; } HeroNode2 temp = head.next; boolean isDelete = false ; while (true ) { if (temp == null ) { break ; } if (temp.no == no) { temp.pre.next = temp.next; if (temp.next != null ) { temp.next.pre = temp.pre; } isDelete = true ; break ; } temp = temp.next; } System.out.println(isDelete ? "删除成功" : "没有找到该节点的信息" ); } public void update (HeroNode2 newHeroNode) { if (head.next == null ) { System.out.println("链表为空,无法修改该节点!" ); return ; } HeroNode2 temp = head.next; boolean idFind = false ; while (true ) { if (temp == null ) { break ; } if (temp.no == newHeroNode.no) { temp.name = newHeroNode.name; temp.nickname = newHeroNode.nickname; idFind = true ; break ; } temp = temp.next; } System.out.println(idFind ? "修改成功" : "没有找到该节点的信息" ); } public void add (HeroNode2 heroNode) { HeroNode2 temp = head; while (temp.next != null ) { temp = temp.next; } temp.next = heroNode; heroNode.pre = temp; } public void list () { if (head.next == null ) { System.out.println("链表为空!" ); return ; } HeroNode2 temp = head; while (temp.next != null ) { System.out.println(temp.next); temp = temp.next; } } } class HeroNode2 { public int no; public String name; public String nickname; public HeroNode2 next; public HeroNode2 pre; public HeroNode2 (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 + '\'' + '}' ; } }
4.4 单向环形链表的应用场景(Josephu问题) Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
解决的方案:用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从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 package com.atguigu.linkedlist;public class Josephu { public static void main (String[] args) { CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList (); circleSingleLinkedList.addBoy(5 ); circleSingleLinkedList.showBoy(); circleSingleLinkedList.countBoy(1 ,2 ,5 ); } } class CircleSingleLinkedList { private Boy first = null ; public void countBoy (int startNo, int countNum, int nums) { if (first == null || startNo < 0 || startNo > nums) { System.out.println("参数输入有误,请重新输入!" ); return ; } Boy helper = first; while (true ) { if (helper.getNext() == first) { break ; } helper = helper.getNext(); } for (int i = 0 ; i < startNo - 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" ,helper.getNo()); } public void showBoy () { if (first == null ) { System.out.println("环形链表为空!" ); return ; } Boy curBoy = first; while (true ) { System.out.printf("小孩的编号:%d \n" , curBoy.getNo()); if (curBoy.getNext() == first) { break ; } curBoy = curBoy.getNext(); } } public void addBoy (int nums) { if (nums < 1 ) { System.out.println("输入的值不正确!" ); return ; } Boy curBoy = null ; for (int i = 1 ; i <= nums; i++) { Boy boy = new Boy (i); if (i == 1 ) { first = boy; first.setNext(first); curBoy = first; } else { curBoy.setNext(boy); boy.setNext(first); curBoy = boy; } } } } class Boy { private int no; private Boy next; public Boy (int no) { this .no = no; } public int getNo () { return no; } public void setNo (int no) { this .no = no; } public Boy getNext () { return next; } public void setNext (Boy next) { this .next = next; } }
五.栈 1.介绍 1)栈的英文为(stack)
2)栈是一个先入后出 (FILO-First In Last Out)的有序列表。
3)栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端 进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶 (Top),另一端为固定的一端,称为栈底 (Bottom)。
4)根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除
2.应用场景 1)子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以回到原来的程序中。
2)处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。
3)表达式的转换[中缀表达式转后缀表达式]与求值(实际解决)。
4)二叉树的遍历。
5)图形的深度优先(depth一first)搜索法。
3.图解
4.使用数组模拟栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 package com.atguigu.stack;public class ArrayStackDemo { public static void main (String[] args) { ArrayStack stack = new ArrayStack (5 ); stack.push(1 ); stack.push(2 ); stack.push(3 ); System.out.println("出栈的数是:" +stack.pop()); stack.list(); } } 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 list () { if (isEmpty()) { System.out.println("栈空,无法取出数据!" ); return ; } for (int i = top; i >= 0 ; i--) { System.out.printf("stack[%d] = %d \n" , i, stack[i]); } } }
5.栈实现综合计算器 中缀表达式
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 package com.atguigu.stack;public class Calculator { public static void main (String[] args) { String expression = "30+2*6-2" ; ArrayStack2 numStack = new ArrayStack2 (10 ); ArrayStack2 operStack = new ArrayStack2 (10 ); int index = 0 ; int num1 = 0 ; int num2 = 0 ; int oper = 0 ; int result = 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(); result = numStack.cal(num1, num2, oper); numStack.push(result); 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 ; } num1 = numStack.pop(); num2 = numStack.pop(); oper = operStack.pop(); result = numStack.cal(num1, num2, oper); numStack.push(result); } System.out.printf("表达式:%s = %d" , expression, numStack.pop()); } } class ArrayStack2 { private int maxSize; private int [] stack; private int top = -1 ; public ArrayStack2 (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 list () { 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 result = 0 ; switch (oper) { case '+' : result = num1 + num2; break ; case '-' : result = num2 - num1; break ; case '*' : result = num1 * num2; break ; case '/' : result = num2 / num1; } return result; } public int peek () { return stack[top]; } }
6.逆波兰计算器的设计与实现 逆波兰表达式(后缀表达式)
1)输入一个逆波兰表达式(后缀表达式),使用栈(Stack),计算其结果
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 package com.atguigu.stack;import java.util.ArrayList;import java.util.List;import java.util.Stack;public class PolandNotation { public static void main (String[] args) { String suffixExpression = "3 4 + 5 * 6 -" ; List<String> rpnList = getListString(suffixExpression); System.out.println("计算的结果是:" +calculate(rpnList)); } 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> list) { Stack<String> stack = new Stack <>(); for (String item : list) { if (item.matches("\\d+" )) { stack.push(item); } else { int num2 = Integer.parseInt(stack.pop()); int num1 = Integer.parseInt(stack.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 ("运算符有误!" ); } stack.push(res + "" ); } } return Integer.parseInt(stack.pop()); } }
将中缀表达式转化为后缀表达式(逆波兰表达式)
解题的步骤:
1)初始化两个栈:运算符栈s1和储存中间结果的栈s2;
2)从左至右扫描中缀表达式;
3)遇到操作数时,将其压s2;
4)遇到运算符时,比较其与s1栈顶运算符的优先级:
(1)如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
(2)否则,若优先级比栈顶运算符的高,也将运算符压入s1;
(3)否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较
5)遇到括号时: (1) 如果是左括号“(”,则直接压入s1 (2) 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
6)重复步骤2至5,直到表达式的最右边
7)将s1中剩余的运算符依次弹出并压入s2
8)依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
先将中缀表达式转化成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 public static List<String> toInfixExpressionList (String expression) { List<String> list = new ArrayList <>(); int i = 0 ; String str; char c; do { if ((c = expression.charAt(i)) < 48 || (c = expression.charAt(i)) > 57 ) { list.add(c + "" ); i++; } else { str = "" ; while (i < expression.length() && (c = expression.charAt(i)) >= 48 && (c = expression.charAt(i)) <= 57 ) { str += c; i++; } list.add(str); } } while (i < expression.length()); 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 public static List<String> parseSuffixExpressionList (List<String> ls) { Stack<String> s1 = new Stack <>(); ArrayList<String> s2 = new ArrayList <>(); for (String item : ls) { if (item.matches("\\d+" )) { s2.add(item); } else if (item.equals("(" )) { s1.push(item); } else if (item.equals(")" )) { while (!s1.peek().equals("(" )) { s2.add(s1.pop()); } s1.pop(); } else { while (s1.size() != 0 && getVal(s1.peek()) >= getVal(item)) { s2.add(s1.pop()); } s1.push(item); } } while (s1.size() != 0 ) { s2.add(s1.pop()); } return s2; }
通过逆波兰表达式(后缀表达式)的集合得到最终的计算结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public static int calculate (List<String> list) { Stack<String> stack = new Stack <>(); for (String item : list) { if (item.matches("\\d+" )) { stack.push(item); } else { int num2 = Integer.parseInt(stack.pop()); int num1 = Integer.parseInt(stack.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 ("运算符有误!" ); } stack.push(res + "" ); } } return Integer.parseInt(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 184 185 186 187 188 189 190 191 192 193 194 package com.atguigu.stack;import java.util.ArrayList;import java.util.List;import java.util.Stack;public class PolandNotation { public static void main (String[] args) { String suffixExpression = "3 4 + 5 * 6 -" ; List<String> rpnList = getListString(suffixExpression); System.out.println("计算的结果是:" + calculate(rpnList)); String expression = "1+((2+3)*4)-5" ; List<String> list = toInfixExpressionList(expression); System.out.println("中缀表达式对应的List:" + list); List<String> stringList = parseSuffixExpressionList(list); System.out.println("中缀表达式对应的List:" + stringList); System.out.println("计算的结果:" + calculate(stringList)); } public static int getVal (String operation) { int res = 0 ; switch (operation) { case "+" : case "-" : res = 1 ; break ; case "/" : case "*" : res = 2 ; break ; default : break ; } return res; } public static List<String> parseSuffixExpressionList (List<String> ls) { Stack<String> s1 = new Stack <>(); ArrayList<String> s2 = new ArrayList <>(); for (String item : ls) { if (item.matches("\\d+" )) { s2.add(item); } else if (item.equals("(" )) { s1.push(item); } else if (item.equals(")" )) { while (!s1.peek().equals("(" )) { s2.add(s1.pop()); } s1.pop(); } else { while (s1.size() != 0 && getVal(s1.peek()) >= getVal(item)) { s2.add(s1.pop()); } s1.push(item); } } while (s1.size() != 0 ) { s2.add(s1.pop()); } return s2; } public static List<String> toInfixExpressionList (String expression) { List<String> list = new ArrayList <>(); int i = 0 ; String str; char c; do { if ((c = expression.charAt(i)) < 48 || (c = expression.charAt(i)) > 57 ) { list.add(c + "" ); i++; } else { str = "" ; while (i < expression.length() && (c = expression.charAt(i)) >= 48 && (c = expression.charAt(i)) <= 57 ) { str += c; i++; } list.add(str); } } while (i < expression.length()); return list; } 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> list) { Stack<String> stack = new Stack <>(); for (String item : list) { if (item.matches("\\d+" )) { stack.push(item); } else { int num2 = Integer.parseInt(stack.pop()); int num1 = Integer.parseInt(stack.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 ("运算符有误!" ); } stack.push(res + "" ); } } return Integer.parseInt(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 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 package com.atguigu.stack;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 = "/" ; 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 = 0d ; 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; } 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(); } } }
六.递归 1.简单介绍 递归就是方法自己调用自己,每次调用时传入不同的变量,递归有助于编程者解决复杂的问题 ,同时可以让代码变得简洁
2.入门案例
3.递归解决的问题 1)各种数学问题如: 8皇后问题 , 汉诺塔, 阶乘问题, 迷宫问题, 球和篮子的问题(google编程大赛)
2)各种算法中也会使用到递归,比如快排,归并排序,二分查找,分治算法等.
3)将用栈解决的问题–>第归代码比较简洁
4.递归遵循的规则 1)执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
2)方法的局部变量是独立的,不会相互影响, 比如n变量
3)如果方法中使用的是引用类型变量(比如数组),就会共享该引用类型的数据.
4)递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError,死龟了:)
5)当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。
5.递归的实际应用 5.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 package com.atguigu.recursion;public class MiGong { public static void main (String[] args) { int [][] map = new int [8 ][7 ]; for (int i = 0 ; i < 7 ; i++) { map[0 ][i] = 1 ; map[7 ][i] = 1 ; } for (int i = 0 ; i < 8 ; i++) { map[i][0 ] = 1 ; map[i][6 ] = 1 ; } map[3 ][1 ] = 1 ; map[3 ][2 ] = 1 ; showMap(map); getWay(map, 1 , 1 ); System.out.println("标识过的路" ); showMap(map); } public static void showMap (int [][] map) { for (int i = 0 ; i < map.length; i++) { for (int j = 0 ; j < map[i].length; j++) { System.out.print(map[i][j] + " " ); } System.out.println(); } } public static boolean getWay (int [][] map, int i, int j) { if (map[6 ][5 ] == 2 ) { return true ; } else { if (map[i][j] == 0 ) { map[i][j] = 2 ; if (getWay(map, i + 1 , j)) { return true ; } else if (getWay(map, i, j + 1 )) { return true ; } else if (getWay(map, i - 1 , j)) { return true ; } else if (getWay(map, i, j - 1 )) { return true ; } else { map[i][j] = 3 ; return false ; } } else { return false ; } } } }
5.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 package com.atguigu.recursion;public class Queue8 { public static void main (String[] args) { Queue8 queue8 = new Queue8 (); queue8.check(0 ); } int max = 8 ; int [] array = new int [max]; int count = 0 ; public 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 ); } } } public boolean judge (int n) { 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 () { System.out.println("第" + (++count) + "中摆法" ); int [][] arr = new int [max][max]; for (int i = 0 ; i < array.length; i++) { arr[i][array[i]] = 1 ; } for (int [] ints : arr) { for (int i : ints) { System.out.print(i + " " ); } System.out.println(); } } }
七.排序算法 十大经典的排序算法: 菜鸟教程排序算法
1.介绍
2.时间复杂度 度量时间复杂度的两种方法
事后统计法的不足:
需要实际的运行程序 比较耗时
受计算机硬件和软件的影响
时间频度
基本的介绍:一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度 。记为T(n)
时间复杂度介绍
常见的时间复杂度
3.空间复杂度
排序算法的时间和空间复杂度
4.冒泡排序 冒泡排序的时间复杂度:o(n^2)
同一台电脑 8万个数据 十几秒左右
4.1 基本介绍
4.2 图解
4.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 package com.atguigu.sort;import java.util.Arrays;public class BubbleSort { public static void main (String[] args) { int arr[] = {3 , 9 , -1 , 10 , -2 }; BubbleSort.sort(arr); } public static void sort (int [] arr) { for (int i = 0 ; i < arr.length - 1 ; i++) { int temp = 0 ; for (int j = 0 ; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1 ]) { temp = arr[j]; arr[j] = arr[j + 1 ]; arr[j + 1 ] = temp; } } System.out.println("第" + (i + 1 ) + "次排序:" + Arrays.toString(arr)); } System.out.println("排序之后的数组:" + Arrays.toString(arr)); } }
优化之后的代码(如果排序的过程中代码有序就不在排序)
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 package com.atguigu.sort;import java.util.Arrays;public class BubbleSort { public static void main (String[] args) { int arr[] = {3 , 9 , -1 , 10 , -2 }; BubbleSort.sort(arr); } public static void sort (int [] arr) { for (int i = 0 ; i < arr.length - 1 ; i++) { int temp = 0 ; boolean flag = false ; for (int j = 0 ; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1 ]) { flag = true ; temp = arr[j]; arr[j] = arr[j + 1 ]; arr[j + 1 ] = temp; } } System.out.println("第" + (i + 1 ) + "次排序:" + Arrays.toString(arr)); if (!flag){ break ; } } System.out.println("排序之后的数组:" + Arrays.toString(arr)); } }
5.选择排序 5.1 基本介绍 同一台电脑 8万个数据 两秒左右
选择式排序也属于内部排序法,是从欲排序的数据中,按指定的规则选出某一元素,再依规定交换位置后达到排序的目的
5.2图解
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 package com.atguigu.sort;import java.util.Arrays;public class SelectSort { public static void main (String[] args) { int [] arr = {101 ,34 ,119 ,1 }; int [] arr1 = {3 , 9 , -1 , 10 , -2 }; int [] arr2 = {3 , 9 , -1 , 10 , -2 }; System.out.println("自己的代码" ); SelectSort.selectSort(arr2); System.out.println("老师的代码" ); SelectSort.selectSortByTeacher(arr1); } public static void selectSort (int [] arr) { for (int i = 0 ; i < arr.length - 1 ; i++) { for (int j = i + 1 ; j < arr.length; j++) { int temp = 0 ; if (arr[i] > arr[j]) { temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } System.out.println("第次" +(i+1 )+"排序的结果:" +Arrays.toString(arr)); } System.out.println("最终的结果:" +Arrays.toString(arr)); } public static void selectSortByTeacher (int [] arr) { for (int i = 0 ; i < arr.length - 1 ; i++) { int minIndex = i; int min = arr[i]; for (int j = i + 1 ; j < arr.length; j++) { if (min > arr[j]){ min = arr[j]; minIndex = j; } } arr[minIndex] = arr[i]; arr[i] = min; System.out.println("第次" +(i+1 )+"排序的结果:" +Arrays.toString(arr)); } System.out.println("最终的结果:" +Arrays.toString(arr)); } }
6.插入排序 6.1 基本介绍 同一台电脑 8万个数据 五秒左右
插入式排序属于内部排序法,是对于欲排序的元素以插入的方式找寻该元素的适当位置,以达到排序的目的。
6.2 图解
6.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 package com.atguigu.sort;import java.util.Arrays;public class InsertSort { public static void main (String[] args) { int [] arr = {101 , 34 , 119 , 1 ,-1 ,89 }; System.out.println("插入前的数组:" +Arrays.toString(arr)); InsertSort.insertSort(arr); } public static void insertSort (int [] arr) { for (int i = 1 ; i < arr.length; i++) { int insertVal = arr[i]; int insertIndex = i - 1 ; while (insertIndex >= 0 && insertVal < arr[insertIndex]) { arr[insertIndex + 1 ] = arr[insertIndex]; insertIndex--; } arr[insertIndex + 1 ] = insertVal; System.out.println("第" + i + "次插入的结果:" + Arrays.toString(arr)); } System.out.println("最终的结果:" + Arrays.toString(arr)); } }
7.希尔排序 7.1基本介绍 同一台电脑 8万个数据 十七秒左右(交换法)
同一台电脑 8万个数据 一秒左右(移动法)
7.2.图解
7.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 package com.atguigu.sort;import java.util.Arrays;public class ShellSort { public static void main (String[] args) { int [] arr = {8 , 9 , 1 , 7 , 2 , 3 , 5 , 4 , 6 , 0 }; shellSort2(arr); } public static void shellSort (int [] arr) { int temp = 0 ; int count = 0 ; for (int gap = arr.length / 2 ; gap > 0 ; gap /= 2 ) { for (int i = gap; i < arr.length; i++) { for (int j = i - gap; j >= 0 ; j -= gap) { if (arr[j] > arr[j + gap]) { temp = arr[j]; arr[j] = arr[j + gap]; arr[j + gap] = temp; } } } System.out.println("排序第" + (++count) + "轮的结果:" + Arrays.toString(arr)); } System.out.println("最终的结果:" + Arrays.toString(arr)); } public static void shellSort2 (int [] arr) { int count = 0 ; for (int gap = arr.length / 2 ; gap > 0 ; gap /= 2 ) { for (int i = gap; i < arr.length; i++) { int j = i; int temp = arr[j]; if (arr[j] < arr[j - gap]) { while (j - gap >= 0 && temp < arr[j - gap]) { arr[j] = arr[j - gap]; j -= gap; } arr[j] = temp; } } System.out.println("排序第" + (++count) + "轮的结果:" + Arrays.toString(arr)); } System.out.println("最终的结果:" + Arrays.toString(arr)); } }
8.快速排序 8.1 基本介绍 同一台电脑 8万个数据 不到一秒 800万个数据两秒钟
快速排序(Quicksort)是对冒泡排序的一种改进。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
8.2 图解
8.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 package com.atguigu.sort;import java.util.Arrays;public class QuickSort { public static void main (String[] args) { int [] arr = {-9 , 78 , 0 , 23 , -567 , 70 }; quickSort(arr, 0 , arr.length - 1 ); System.out.println(Arrays.toString(arr)); } public static void quickSort (int [] arr, int left, int right) { int l = left; int r = right; int pivot = arr[(left + right) / 2 ]; int temp = 0 ; while (l < r) { while (arr[l] < pivot) { l += 1 ; } while (arr[r] > pivot) { r -= 1 ; } if (l >= r) { break ; } temp = arr[l]; arr[l] = arr[r]; arr[r] = temp; if (arr[l] == pivot) { r--; } if (arr[r] == pivot) { l++; } } if (l == r) { l += 1 ; r -= 1 ; } if (left < r) { quickSort(arr, left, r); } if (right > l) { quickSort(arr, l, right); } } }
9. 归并排序 9.1基本介绍 同一台电脑 8万个数据 大约一秒钟 800万个数据三秒
9.2 图解
9.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 package com.atguigu.sort;import java.util.Arrays;public class MergeSort { public static void main (String[] args) { int [] arr = {8 , 4 , 5 , 7 , 1 , 3 , 6 , 2 }; int [] temp = new int [arr.length]; mergeSort(arr,0 , arr.length -1 ,temp); System.out.println("归并排序之后的数组:" + Arrays.toString(arr)); } public static void mergeSort (int [] arr, int left, int right, int [] temp) { if (left < right){ int mid = (left + right) / 2 ; mergeSort(arr,left,mid,temp); mergeSort(arr,mid+1 ,right,temp); merge(arr,left,mid,right,temp); } } public static void merge (int [] arr, int left, int mid, int right, int [] temp) { int i = left; int j = mid + 1 ; int t = 0 ; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) { temp[t] = arr[i]; t++; i++; } else { temp[t] = arr[j]; t++; j++; } } while (i <= mid) { temp[t] = arr[i]; t++; i++; } while (j <= right) { temp[t] = arr[j]; t++; j++; } t = 0 ; int tempLeft = left; while (tempLeft <= right) { arr[tempLeft] = temp[t]; t++; tempLeft++; } } }
10.基数排序 同一台电脑8万个数据 一秒左右 8千万个数据会报内存不足
10.1 基本介绍
10.2 图解
10.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 package com.atguigu.sort;import java.util.Arrays;public class RadixSort { public static void main (String[] args) { int arr[] = {53 , 3 , 542 , 748 , 14 , 214 }; RadixSort.radixSort(arr); } public static void radixSort (int [] arr) { int [][] bucket = new int [10 ][arr.length]; int [] bucketElementCounts = new int [10 ]; for (int j = 0 ; j < arr.length; j++) { int digitOfElement = arr[j] % 10 ; bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j]; bucketElementCounts[digitOfElement]++; } int index = 0 ; for (int k = 0 ; k < bucketElementCounts.length; k++) { if (bucketElementCounts[k] != 0 ) { for (int l = 0 ; l < bucketElementCounts[k]; l++) { arr[index++] = bucket[k][l]; } } bucketElementCounts[k] = 0 ; } System.out.println("第一轮:" + Arrays.toString(arr)); for (int j = 0 ; j < arr.length; j++) { int digitOfElement = arr[j] / 10 % 10 ; bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j]; bucketElementCounts[digitOfElement]++; } index = 0 ; for (int k = 0 ; k < bucketElementCounts.length; k++) { if (bucketElementCounts[k] != 0 ) { for (int l = 0 ; l < bucketElementCounts[k]; l++) { arr[index++] = bucket[k][l]; } } bucketElementCounts[k] = 0 ; } System.out.println("第2轮:" + Arrays.toString(arr)); for (int j = 0 ; j < arr.length; j++) { int digitOfElement = arr[j] / 100 % 10 ; bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j]; bucketElementCounts[digitOfElement]++; } index = 0 ; for (int k = 0 ; k < bucketElementCounts.length; k++) { if (bucketElementCounts[k] != 0 ) { for (int l = 0 ; l < bucketElementCounts[k]; l++) { arr[index++] = bucket[k][l]; } } } System.out.println("第3轮:" + Arrays.toString(arr)); } }
最终代码
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 package com.atguigu.sort;import java.util.Arrays;public class RadixSort { public static void main (String[] args) { int arr[] = {53 , 3 , 542 , 748 , 14 , 214 }; RadixSort.radixSort(arr); } public static void radixSort (int [] arr) { int max = arr[0 ]; for (int i = 0 ; i < arr.length; i++) { if (arr[i] > max) { max = arr[i]; } } int maxLength = (max + "" ).length(); int [][] bucket = new int [10 ][arr.length]; int [] bucketElementCounts = new int [10 ]; for (int i = 0 , n = 1 ; i < maxLength; i++, n *= 10 ) { for (int j = 0 ; j < arr.length; j++) { int digitOfElement = arr[j] / n % 10 ; bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j]; bucketElementCounts[digitOfElement]++; } int index = 0 ; for (int k = 0 ; k < bucketElementCounts.length; k++) { if (bucketElementCounts[k] != 0 ) { for (int l = 0 ; l < bucketElementCounts[k]; l++) { arr[index++] = bucket[k][l]; } } bucketElementCounts[k] = 0 ; } System.out.println("第" + (i + 1 ) + "轮:" + Arrays.toString(arr)); } } }
11.常用排序算法总结和对比
八.查找算法 1.简单介绍
2.线性查找算法 2.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 package com.atguigu.search;public class SeqSearch { public static void main (String[] args) { int [] arr = {1 ,9 ,11 ,-1 ,34 ,89 }; System.out.println("目标值的下标:" +seqSearch(arr, 11 )); } public static int seqSearch (int [] arr,int value) { for (int i = 0 ; i < arr.length; i++) { if (arr[i] == value){ return i; } } return -1 ; } }
3.二分查找算法 3.1 图解
3.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 package com.atguigu.search;public class BinarySearch { public static void main (String[] args) { int [] arr = {1 , 8 , 10 , 89 , 1000 , 1234 }; System.out.println("目标值的下标:" + binarySearch(arr, 0 , arr.length - 1 , 3 )); } public static int binarySearch (int [] arr, int left, int right, int findVal) { if (left > right) { return -1 ; } int mid = (left + right) / 2 ; int midVal = arr[mid]; if (findVal > midVal) { return binarySearch(arr, mid + 1 , right, findVal); } else if (findVal < midVal) { return binarySearch(arr, left, mid - 1 , findVal); } else { return mid; } } }
完整的代码
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 package com.atguigu.search;import java.util.ArrayList;import java.util.List;public class BinarySearch { public static void main (String[] args) { int [] arr = {1 , 8 , 10 , 89 , 1000 , 1234 }; System.out.println("目标值的下标:" + binarySearch(arr, 0 , arr.length - 1 , 3 )); int [] arr2 = {1 , 8 , 10 , 89 , 89 , 89 , 1000 , 1234 }; System.out.println("目标值在数组中下标的集合:" + binarySearch2(arr2, 0 , arr2.length - 1 , 89 )); } public static int binarySearch (int [] arr, int left, int right, int findVal) { if (left > right) { return -1 ; } int mid = (left + right) / 2 ; int midVal = arr[mid]; if (findVal > midVal) { return binarySearch(arr, mid + 1 , right, findVal); } else if (findVal < midVal) { return binarySearch(arr, left, mid - 1 , findVal); } else { return mid; } } public static List<Integer> binarySearch2 (int [] arr, int left, int right, int findVal) { if (left > right) { return new ArrayList <>(); } int mid = (left + right) / 2 ; int midVal = arr[mid]; if (findVal > midVal) { return binarySearch2(arr, mid + 1 , right, findVal); } else if (findVal < midVal) { return binarySearch2(arr, left, mid - 1 , findVal); } else { List<Integer> resList = new ArrayList <>(); int temp = mid - 1 ; while (true ) { if (temp < 0 || arr[temp] != findVal) { break ; } resList.add(temp); temp--; } resList.add(mid); temp = mid + 1 ; while (true ) { if (temp > arr.length - 1 || arr[temp] != findVal) { break ; } resList.add(temp); temp++; } return resList; } } }
4.插值查找算法 4.1 图解
4.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 package com.atguigu.search;import java.util.Arrays;public class InsertValueSearch { public static void main (String[] args) { int [] arr = new int [100 ]; for (int i = 0 ; i < 100 ; i++) { arr[i] = i + 1 ; } System.out.println(Arrays.toString(arr)); System.out.println("查找的数的下标为:" + insertValueSearch(arr, 0 , arr.length - 1 , 30 )); } public static int insertValueSearch (int [] arr, int left, int right, int findVal) { System.out.println("方法被调用了" ); if (left > right || findVal < arr[0 ] || findVal > arr[arr.length - 1 ]) { return -1 ; } int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]); int midVal = arr[mid]; if (findVal > midVal) { return insertValueSearch(arr, mid + 1 , right, findVal); } else if (findVal < midVal) { return insertValueSearch(arr, left, mid - 1 , findVal); } else { return mid; } } }
4.3 注意事项
5.斐波那契(黄金分割法)查找算法 5.1 基本介绍
5.2 原理介绍
PDF笔记