├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src └── main └── java └── me └── irfen └── algorithm ├── ch01 ├── ArrayList.java ├── ArrayListTest.java ├── Entry.java ├── HashTable.java └── HashTableTest.java ├── ch02 ├── ArrayQueue.java ├── ArrayQueueTest.java ├── Link.java ├── LinkTest.java ├── Node.java ├── Stack.java ├── StackTest.java └── extend │ ├── Element.java │ ├── HanoiTest.java │ ├── LinkReverseTest.java │ ├── Queue2Stack.java │ ├── Queue2StackTest.java │ ├── Stack2Queue.java │ ├── Stack2QueueTest.java │ ├── StaticLinkedList.java │ └── StaticLinkedListTest.java ├── ch03 ├── BubbleSort.java ├── BucketSort.java ├── InsertSort.java ├── QuickSort.java ├── SelectSort.java ├── ShellSort.java └── SortTest.java ├── ch04 ├── BinarySearch.java ├── BinarySearchTest.java ├── BinarySort.java ├── BlockSearch.java ├── BlockSearchTest.java ├── SequentialSearch.java ├── YoungSearch.java └── YoungSearchTest.java ├── ch05 ├── BinarySearchingTree.java ├── BinaryTree.java ├── BinaryTreeNode.java ├── BinaryTreeNode2.java ├── Heap.java ├── HeapSortTest.java ├── HeapTest.java ├── Test.java ├── TreeNode1.java └── TreeNode2.java ├── ch06 ├── DijkstraTest.java ├── ListGraph.java ├── ListGraphNode.java ├── ListGraphTest.java ├── MatrixGraph.java └── MatrixGraphTest.java ├── ch07 ├── FullPermutation.java ├── FullPermutationTest.java ├── Reverse.java ├── ReverseTest.java ├── StringContainsUtil.java ├── StringContainsUtilTest.java ├── StringUtils.java └── StringUtilsTest.java ├── ch08 ├── ArrayDot.java ├── ArrayDotTest.java ├── ArraySort.java ├── ArraySortTest.java ├── AssignArray.java ├── AssignArrayTest.java ├── DutchFlag.java ├── DutchFlagTest.java ├── MaxSumSubArray.java ├── MaxSumSubArrayTest.java ├── RandomArray.java ├── RandomArrayTest.java ├── TwoSum.java └── TwoSumTest.java ├── ch09 ├── FindK.java ├── FindKTest.java ├── LostNumber.java ├── LostNumberTest.java ├── MoreThanHalf.java └── MoreThanHalfTest.java └── ch11 ├── ArrayList.java ├── ArrayListTest.java ├── HashMap.java ├── HashMapTest.java ├── Stack.java └── StackTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/ 3 | *.iml 4 | target/ 5 | 6 | # Compiled class file 7 | *.class 8 | 9 | # Log file 10 | *.log 11 | 12 | # BlueJ files 13 | *.ctxt 14 | 15 | # Mobile Tools for Java (J2ME) 16 | .mtj.tmp/ 17 | 18 | # Package Files # 19 | *.jar 20 | *.war 21 | *.ear 22 | *.zip 23 | *.tar.gz 24 | *.rar 25 | 26 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 27 | hs_err_pid* 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # easyAlgorithm 2 | 《轻松学算法》一书内所有代码示例。内容比较简单,欢迎对算法有兴趣,或者入门级别的同学选购。京东经常无货,当当一般有货。 3 | 4 | 欢迎各种转载,但请注明本github地址。 5 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.irfen 8 | algorithm 9 | 1.0-SNAPSHOT 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch01/ArrayList.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch01; 2 | 3 | import java.util.Arrays; 4 | 5 | public class ArrayList { 6 | 7 | private static final int INITIAL_SIZE = 10; 8 | 9 | private int size = 0; 10 | 11 | private int[] array; 12 | 13 | public ArrayList() { 14 | array = new int[INITIAL_SIZE]; 15 | } 16 | 17 | public ArrayList(int initial) { 18 | if (initial <= 0) { 19 | initial = INITIAL_SIZE; 20 | } 21 | array = new int[initial]; 22 | } 23 | 24 | /** 25 | * 添加元素 26 | * @param num 27 | */ 28 | public void add(int num) { 29 | if (size == array.length) { 30 | array = Arrays.copyOf(array, size * 2); 31 | } 32 | array[size++] = num; 33 | } 34 | 35 | /** 36 | * 获取指定位置的元素值 37 | * @param i 38 | * @return 39 | */ 40 | public int get(int i) { 41 | if (i >= size) { 42 | throw new IndexOutOfBoundsException("获取的元素位置超过了最大长度"); 43 | } 44 | return array[i]; 45 | } 46 | 47 | /** 48 | * 设置指定位置的元素值 49 | * @param i 50 | * @param num 51 | * @return 52 | */ 53 | public int set(int i, int num) { 54 | int oldNum = get(i); 55 | array[i] = num; 56 | return oldNum; 57 | } 58 | 59 | /** 60 | * 获取变长数组的长度 61 | * @return 62 | */ 63 | public int size() { 64 | return size; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch01/ArrayListTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch01; 2 | 3 | public class ArrayListTest { 4 | 5 | public static void main(String[] args) { 6 | ArrayList arrayList = new ArrayList(1); 7 | arrayList.add(1); 8 | arrayList.add(2); 9 | arrayList.add(3); 10 | arrayList.add(4); 11 | arrayList.add(5); 12 | System.out.println(arrayList.get(3)); // 获取数组下标为3的值,其实也就是第4个位置的值,打印4 13 | arrayList.set(3, 9); // 设置第4个位置的值为9 14 | System.out.println(arrayList.get(3)); // 再次获取,这次打印9了 15 | System.out.println(arrayList.size());// 变长数组长度为5,实际上内部数组长度为8,在add(2)和add(5)时,分别进行了数组长度翻倍及数组拷贝 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch01/Entry.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch01; 2 | 3 | public class Entry { 4 | int key; 5 | int value; 6 | Entry next; 7 | 8 | public Entry(int key, int value, Entry next) { 9 | super(); 10 | this.key = key; 11 | this.value = value; 12 | this.next = next; 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch01/HashTable.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch01; 2 | 3 | public class HashTable { 4 | 5 | /** 6 | * 默认散列表初始化长度 7 | * 设置小点我们能够清楚看到扩容 8 | * 实际使用中其实可以在初始化的时候传参,要知道,扩容也是很消耗性能的 9 | */ 10 | private static final int DEFAULT_INITIAL_CAPACITY = 4; 11 | 12 | /** 13 | * 扩容因子 14 | */ 15 | private static final float LOAD_FACTOR = 0.75f; 16 | 17 | /** 18 | * 散列表数组 19 | */ 20 | private Entry[] table = new Entry[DEFAULT_INITIAL_CAPACITY]; 21 | private int size = 0; // 散列表元素个数 22 | private int use = 0; // 散列表使用地址个数 23 | 24 | /** 25 | * 添加/修改 26 | * @param key 27 | * @param value 28 | */ 29 | public void put(int key, int value) { 30 | int index = hash(key); 31 | if (table[index] == null) { 32 | table[index] = new Entry(-1, -1, null); 33 | } 34 | Entry e = table[index]; 35 | if (e.next == null) { 36 | // 不存在值,向链表添加,有可能扩容,要用table属性 37 | table[index].next = new Entry(key, value, null); 38 | size ++; 39 | use ++; 40 | // 不存在值,说明是个未用过的地址,需要判断是否需要扩容 41 | if (use >= table.length * LOAD_FACTOR) { 42 | resize(); 43 | } 44 | } else { 45 | // 本身存在值,修改已有的值 46 | for (e = e.next; e != null; e = e.next) { 47 | int k = e.key; 48 | if (k == key) { 49 | e.value = value; 50 | return; 51 | } 52 | } 53 | // 不存在相同的值,直接往链表添加元素 54 | Entry temp = table[index].next; 55 | Entry newEntry = new Entry(key, value, temp); 56 | table[index].next = newEntry; 57 | size ++; 58 | } 59 | } 60 | 61 | /** 62 | * 删除 63 | * @param key 64 | */ 65 | public void remove(int key) { 66 | int index = hash(key); 67 | Entry e = table[index]; 68 | Entry pre = table[index]; 69 | if (e != null && e.next != null) { 70 | for (e = e.next; e != null; pre = e, e = e.next) { 71 | int k = e.key; 72 | if (k == key) { 73 | pre.next = e.next; 74 | size --; 75 | return; 76 | } 77 | } 78 | } 79 | } 80 | 81 | /** 82 | * 获取 83 | * @param key 84 | * @return 85 | */ 86 | public int get(int key) { 87 | int index = hash(key); 88 | Entry e = table[index]; 89 | if (e != null && e.next != null) { 90 | for (e = e.next; e != null; e = e.next) { 91 | int k = e.key; 92 | if (k == key) { 93 | return e.value; 94 | } 95 | } 96 | } 97 | // 没有找到返回-1 98 | return -1; 99 | } 100 | 101 | /** 102 | * 获取散列表中元素个数 103 | * @return 104 | */ 105 | public int size() { 106 | return size; 107 | } 108 | 109 | /** 110 | * 本身散列表是不该有这个方法的,把这个放开来只是为了让我们能知道他确实扩容了 111 | * @return 112 | */ 113 | public int getLength() { 114 | return table.length; 115 | } 116 | 117 | /** 118 | * 根据key,通过哈希函数获取位于散列表数组中的哪个位置 119 | * @param key 120 | * @return 121 | */ 122 | private int hash(int key) { 123 | return key % table.length; 124 | } 125 | 126 | /** 127 | * 扩容 128 | */ 129 | private void resize() { 130 | int newLength = table.length * 2; 131 | Entry[] oldTable = table; 132 | table = new Entry[newLength]; 133 | use = 0; 134 | for (int i = 0; i < oldTable.length; i++) { 135 | if (oldTable[i] != null && oldTable[i].next != null) { 136 | Entry e = oldTable[i]; 137 | while(null != e.next) { 138 | Entry next = e.next; 139 | // 重新计算哈希值,放入新的地址中 140 | int index = hash(next.key); 141 | if (table[index] == null) { 142 | use ++; 143 | table[index] = new Entry(-1, -1, null); 144 | } 145 | Entry temp = table[index].next; 146 | Entry newEntry = new Entry(next.key, next.value, temp); 147 | table[index].next = newEntry; 148 | 149 | e = next; 150 | } 151 | } 152 | } 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch01/HashTableTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch01; 2 | 3 | public class HashTableTest { 4 | 5 | public static void main(String[] args) { 6 | HashTable hashTable = new HashTable(); 7 | hashTable.put(1, 10); 8 | hashTable.put(2, 20); 9 | hashTable.put(5, 50); // 和key为1的元素落到一个散列表地址上了,实际使用长度为2 10 | System.out.println(hashTable.getLength()); // 散列表长为4 11 | hashTable.put(3, 30); // 总长为4,加上该元素后长度就大于等于3了,所以扩容 12 | System.out.println(hashTable.getLength()); // 散列表长为8 13 | // 扩容后四个元素又分别落到不同的地址上 14 | hashTable.put(6, 60); // 使用了5个地址 15 | hashTable.put(7, 70); // 使用第6个地址,有为8的0.75倍了,又需要扩容 16 | System.out.println(hashTable.getLength()); // 散列表长为16 17 | System.out.println(hashTable.get(1)); // 10 18 | System.out.println(hashTable.get(3)); // 30 19 | System.out.println(hashTable.get(5)); // 50 20 | System.out.println(hashTable.get(6)); // 60 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/ArrayQueue.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02; 2 | 3 | public class ArrayQueue { 4 | 5 | private final Object[] items; 6 | 7 | private int head = 0; 8 | 9 | private int tail = 0; 10 | 11 | /** 12 | * 初始化队列 13 | * @param capacity 队列长度 14 | */ 15 | public ArrayQueue(int capacity) { 16 | this.items = new Object[capacity]; 17 | } 18 | 19 | /** 20 | * 入队 21 | * @param item 22 | * @return 23 | */ 24 | public boolean put(Object item) { 25 | if (head == (tail + 1) % items.length) { 26 | // 说明队满 27 | return false; 28 | } 29 | items[tail] = item; 30 | tail = (tail + 1) % items.length; // tail标记向后移动一位 31 | return true; 32 | } 33 | 34 | /** 35 | * 获取队列头元素,不出队 36 | * @return 37 | */ 38 | public Object peek() { 39 | if (head == tail) { 40 | // 说明队空 41 | return null; 42 | } 43 | return items[head]; 44 | } 45 | 46 | /** 47 | * 出队 48 | * @return 49 | */ 50 | public Object poll() { 51 | if (head == tail) { 52 | // 说明队空 53 | return null; 54 | } 55 | Object item = items[head]; 56 | items[head] = null; // 把没用的元素赋空值,当然不设置也可以,反正标记移动了,之后会被覆盖 57 | head = (head + 1) % items.length; // head标记向后移动一位 58 | return item; 59 | } 60 | 61 | public boolean isFull() { 62 | return head == (tail + 1) % items.length; 63 | } 64 | 65 | public boolean isEmpty() { 66 | return head == tail; 67 | } 68 | 69 | /** 70 | * 队列元素数 71 | * @return 72 | */ 73 | public int size() { 74 | if (tail >= head) { 75 | return tail - head; 76 | } else { 77 | return tail + items.length - head; 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/ArrayQueueTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02; 2 | 3 | public class ArrayQueueTest { 4 | 5 | public static void main(String[] args) { 6 | ArrayQueue queue = new ArrayQueue(4); 7 | System.out.println(queue.put("A")); // true 8 | System.out.println(queue.put("B")); // true 9 | System.out.println(queue.put("C")); // true 10 | System.out.println(queue.put("D")); // false 11 | 12 | System.out.println(queue.isFull());// true,当前队列已经满了,并且D元素没有入队成功 13 | System.out.println(queue.size()); // 3,队列中有三个元素 14 | 15 | System.out.println(queue.peek()); // A,获取队头元素,不出队 16 | System.out.println(queue.poll()); // A 17 | System.out.println(queue.poll()); // B 18 | System.out.println(queue.poll()); // C 19 | 20 | System.out.println(queue.isEmpty()); // true,当前队列为空队 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/Link.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02; 2 | 3 | public class Link { 4 | 5 | private int size = 0; 6 | 7 | private Node first; 8 | 9 | private Node last; 10 | 11 | /** 12 | * 链表的初始化 13 | */ 14 | public Link() { 15 | } 16 | 17 | /** 18 | * 链表后部插入 19 | * @param data 20 | */ 21 | public void addLast(int data) { 22 | if (size == 0) { 23 | // 为空初始化前后元素 24 | fillStart(data); 25 | } else { 26 | Node node = new Node(); 27 | node.setData(data); 28 | last.setNext(node); 29 | last = node; // 把最后插入的元素设置为链表尾元素 30 | } 31 | size ++; 32 | } 33 | 34 | /** 35 | * 链表头部插入 36 | * @param data 37 | */ 38 | public void addFirst(int data) { 39 | if (size == 0) { 40 | fillStart(data); 41 | } else { 42 | Node node = new Node(); 43 | node.setData(data); 44 | node.setNext(first); // 把元素的下一个位置的指针指向头元素 45 | first = node; // 把刚插入的元素设置为链表头元素 46 | } 47 | size ++; 48 | } 49 | 50 | /** 51 | * 链表指定位置后面插入 52 | * @param data 需要插入的数据 53 | * @param index 下标从0开始 54 | */ 55 | public void add(int data, int index) { 56 | if (size > index) { 57 | if (size == 0) { 58 | // 为空初始化前后元素 59 | fillStart(data); 60 | size ++; 61 | } else if (index == 0) { 62 | addFirst(data); 63 | } else if (size == index + 1) { 64 | // 往最后加的话直接调用addLast 65 | addLast(data); 66 | } else { 67 | Node temp = get(index); 68 | Node node = new Node(); 69 | node.setData(data); 70 | node.setNext(temp.getNext()); 71 | temp.setNext(node); 72 | size ++; 73 | } 74 | } else { 75 | throw new IndexOutOfBoundsException("链表没有那么长哦~"); 76 | } 77 | } 78 | 79 | /** 80 | * 删除链表头部元素 81 | */ 82 | public void removeFirst() { 83 | if (size == 0) { 84 | throw new IndexOutOfBoundsException("链表没有元素的呦~"); 85 | } else if (size == 1) { 86 | // 只剩一个的时候需要清楚first和last 87 | clear(); 88 | } else { 89 | Node temp = first; 90 | first = temp.getNext(); 91 | temp = null; // 帮组空间回收 92 | size --; 93 | } 94 | } 95 | 96 | /** 97 | * 删除链表尾部元素 98 | */ 99 | public void removeLast() { 100 | if (size == 0) { 101 | throw new IndexOutOfBoundsException("链表没有元素的呦~"); 102 | } else if (size == 1) { 103 | // 只剩一个的时候需要清楚first和last 104 | clear(); 105 | } else { 106 | Node temp = get(size - 2); // 获取最后元素之前的一个元素 107 | temp.setNext(null); // 帮组空间回收 108 | size --; 109 | } 110 | } 111 | 112 | /** 113 | * 删除链表中间的元素 114 | * @param index 115 | */ 116 | public void removeMiddle(int index) { 117 | if (size == 0) { 118 | throw new IndexOutOfBoundsException("链表没有元素的呦~"); 119 | } else if (size == 1) { 120 | // 只剩一个的时候需要清楚first和last 121 | clear(); 122 | } else { 123 | if (index == 0) { 124 | removeFirst(); 125 | } else if (size == index - 1) { 126 | removeLast(); 127 | } else { 128 | Node temp = get(index - 1); // 获取要删元素之前的一个元素 129 | Node next = temp.getNext(); 130 | temp.setNext(next.getNext()); 131 | next = null; // 帮组空间回收 132 | size --; 133 | } 134 | } 135 | } 136 | 137 | /** 138 | * 获取指定下标元素 139 | * @param index 140 | * @return 141 | */ 142 | public Node get(int index) { 143 | Node temp = first; 144 | for (int i = 0; i < index; i++) { 145 | temp = temp.getNext(); 146 | } 147 | return temp; 148 | } 149 | 150 | /** 151 | * 打印所有元素数据 152 | */ 153 | public void printAll() { 154 | // 当然也可以用do...while实现 155 | Node temp = first; 156 | System.out.println(temp.getData()); 157 | for (int i = 0; i < size - 1; i++) { 158 | temp = temp.getNext(); 159 | System.out.println(temp.getData()); 160 | } 161 | } 162 | 163 | /** 164 | * 反转链表 165 | */ 166 | public void reverse() { 167 | Node temp = first; 168 | last = temp; 169 | Node next = first.getNext(); 170 | for (int i = 0; i < size - 1; i++) { 171 | Node nextNext = next.getNext(); // 下下个 172 | next.setNext(temp); 173 | temp = next; 174 | next = nextNext; 175 | } 176 | last.setNext(null); 177 | first = temp; 178 | } 179 | 180 | public int size() { 181 | return size; 182 | } 183 | 184 | /** 185 | * 在链表插入第一个元素的时候,头尾元素都是一个元素 186 | * @param data 187 | */ 188 | private void fillStart(int data) { 189 | first = new Node(); 190 | first.setData(data); 191 | last = first; 192 | } 193 | 194 | /** 195 | * 在元素只有一个的时候清除first和last元素 196 | */ 197 | private void clear() { 198 | first = null; 199 | last = null; 200 | size = 0; 201 | } 202 | 203 | } 204 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/LinkTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02; 2 | 3 | public class LinkTest { 4 | 5 | public static void main(String[] args) { 6 | Link link = new Link(); 7 | link.addFirst(2); 8 | link.addFirst(1); 9 | link.addLast(4); 10 | link.addLast(5); 11 | link.add(3, 1); // 在下标为1的元素之后插入元素 12 | printAllElements(link); // 1,2,3,4,5 13 | link.printAll(); // 这样打印效率会更高 14 | link.removeFirst(); 15 | link.removeLast(); 16 | link.removeMiddle(1); 17 | printAllElements(link); // 移除了头尾之后,剩下3个元素,移除下标为1的元素,只剩下两个元素2和4 18 | link.removeFirst(); 19 | link.removeFirst(); 20 | System.out.println(link.size());// 从头部全部移出 21 | 22 | } 23 | 24 | private static void printAllElements(Link link) { 25 | for (int i = 0; i < link.size(); i++) { 26 | System.out.println(link.get(i).getData()); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/Node.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02; 2 | 3 | public class Node { 4 | 5 | private int data; 6 | private Node next; 7 | 8 | public int getData() { 9 | return data; 10 | } 11 | public void setData(int data) { 12 | this.data = data; 13 | } 14 | public Node getNext() { 15 | return next; 16 | } 17 | public void setNext(Node next) { 18 | this.next = next; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/Stack.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02; 2 | 3 | import java.util.Arrays; 4 | 5 | public class Stack { 6 | 7 | private int size = 0; 8 | 9 | private int[] array; 10 | 11 | public Stack() { 12 | this(10); 13 | } 14 | 15 | public Stack(int init) { 16 | if (init <= 0) { 17 | init = 10; 18 | } 19 | array = new int[init]; 20 | } 21 | 22 | /** 23 | * 入栈 24 | * @param item 入栈元素的值 25 | */ 26 | public void push(int item) { 27 | if (size == array.length) { 28 | array = Arrays.copyOf(array, size * 2); 29 | } 30 | array[size++] = item; 31 | } 32 | 33 | /** 34 | * 获取栈顶元素,但是没有出栈 35 | * @return 36 | */ 37 | public int peek() { 38 | if (size == 0) { 39 | throw new IndexOutOfBoundsException("栈里已经空啦"); 40 | } 41 | return array[size - 1]; 42 | } 43 | 44 | /** 45 | * 出栈,同时获取栈顶元素 46 | * @return 47 | */ 48 | public int pop() { 49 | int item = peek(); 50 | size --; // 直接使元素个数减1,不需要真的清除元素,下次入栈会覆盖旧元素值 51 | return item; 52 | } 53 | 54 | /** 55 | * 栈是否满了 56 | * @return 57 | */ 58 | public boolean isFull() { 59 | return size == array.length; 60 | } 61 | 62 | /** 63 | * 栈是否为空栈 64 | * @return 65 | */ 66 | public boolean isEmpty() { 67 | return size == 0; 68 | } 69 | 70 | public int size() { 71 | return size; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/StackTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02; 2 | 3 | public class StackTest { 4 | 5 | public static void main(String[] args) { 6 | Stack stack = new Stack(1); // 为了方便看出效果,设定初始数组长度为1 7 | stack.push(1); 8 | stack.push(2); 9 | System.out.println(stack.size()); // 栈内元素个数为2,当前数组长度也为2 10 | stack.push(3); 11 | System.out.println(stack.size()); // 栈内元素个数为3,当前数组长度为4 12 | System.out.println(stack.peek()); // 获取栈顶元素,为3,但是没有出栈 13 | System.out.println(stack.size()); // 由于上面一行没有出栈,所以元素个数还是3 14 | System.out.println(stack.pop()); // 栈顶元素出栈,返回3 15 | System.out.println(stack.pop()); // 栈顶元素出站,返回2 16 | System.out.println(stack.size()); // 出了两次栈,当前元素个数为1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/extend/Element.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02.extend; 2 | 3 | public class Element { 4 | 5 | private int data; 6 | private int cur; 7 | 8 | public int getData() { 9 | return data; 10 | } 11 | 12 | public void setData(int data) { 13 | this.data = data; 14 | } 15 | 16 | public int getCur() { 17 | return cur; 18 | } 19 | 20 | public void setCur(int cur) { 21 | this.cur = cur; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/extend/HanoiTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02.extend; 2 | 3 | public class HanoiTest { 4 | 5 | public static void hanoi(int n, char A, char B, char C) { 6 | if (n == 1) { 7 | // 只有一个圆盘需要移动的时候移动完结束 8 | move(A, C); 9 | return; 10 | } 11 | // 先把A上的n-1个圆盘移动到B上 12 | hanoi(n - 1, A, C, B); 13 | // 把A上最后一个圆盘移动到C上 14 | move(A, C); 15 | // 接下来递归,把B上的n-1个圆盘移动到C上 16 | hanoi(n - 1, B, A, C); 17 | } 18 | 19 | /** 20 | * 把A最上面的圆盘移动到C上去 21 | * @param A 22 | * @param C 23 | */ 24 | private static void move(char A, char C) { 25 | System.out.println(A + "-->" + C); 26 | } 27 | 28 | public static void main(String[] args) { 29 | hanoi(3, 'A', 'B', 'C'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/extend/LinkReverseTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02.extend; 2 | 3 | import me.irfen.algorithm.ch02.Link; 4 | 5 | public class LinkReverseTest { 6 | 7 | public static void main(String[] args) { 8 | Link link = new Link(); 9 | link.addLast(1); 10 | link.addLast(2); 11 | link.addLast(3); 12 | link.addLast(4); 13 | printAllElements(link); 14 | link.reverse(); 15 | printAllElements(link); 16 | } 17 | 18 | private static void printAllElements(Link link) { 19 | for (int i = 0; i < link.size(); i++) { 20 | System.out.println(link.get(i).getData()); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/extend/Queue2Stack.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02.extend; 2 | 3 | import me.irfen.algorithm.ch02.ArrayQueue; 4 | 5 | public class Queue2Stack { 6 | 7 | private ArrayQueue queue1; 8 | private ArrayQueue queue2; 9 | private int maxLength; 10 | 11 | public Queue2Stack(int capacity) { 12 | maxLength = capacity; 13 | queue1 = new ArrayQueue(capacity); 14 | queue2 = new ArrayQueue(capacity); 15 | } 16 | 17 | /** 18 | * 入栈 19 | * @param item 20 | * @return 入栈结果 21 | */ 22 | public boolean push(int item) { 23 | if (size() == maxLength) { 24 | return false; 25 | } 26 | if (queue2.isEmpty()) { 27 | queue1.put(item); 28 | } else { 29 | queue2.put(item); 30 | } 31 | return true; 32 | } 33 | 34 | /** 35 | * 出栈 36 | * @return 37 | */ 38 | public Object pop() { 39 | if (size() == 0) { 40 | throw new IndexOutOfBoundsException("栈里已经空啦"); 41 | } else { 42 | if (queue2.isEmpty()) { 43 | while (queue1.size() > 1) { 44 | queue2.put(queue1.poll()); 45 | } 46 | return queue1.poll(); 47 | } else { 48 | while (queue2.size() > 1) { 49 | queue1.put(queue2.poll()); 50 | } 51 | return queue2.poll(); 52 | } 53 | } 54 | } 55 | 56 | public int size() { 57 | return queue1.size() + queue2.size(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/extend/Queue2StackTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02.extend; 2 | 3 | public class Queue2StackTest { 4 | 5 | public static void main(String[] args) { 6 | Queue2Stack stack = new Queue2Stack(5); 7 | stack.push(1); 8 | stack.push(2); 9 | System.out.println(stack.pop()); // 2 10 | stack.push(3); 11 | stack.push(4); 12 | System.out.println(stack.pop()); // 4 13 | System.out.println(stack.pop()); // 3 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/extend/Stack2Queue.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02.extend; 2 | 3 | import me.irfen.algorithm.ch02.Stack; 4 | 5 | public class Stack2Queue { 6 | 7 | private Stack stack1; 8 | private Stack stack2; 9 | private int maxLength; 10 | 11 | public Stack2Queue(int capacity) { 12 | maxLength = capacity; 13 | stack1 = new Stack(capacity); 14 | stack2 = new Stack(capacity); 15 | } 16 | 17 | public boolean put(int item) { 18 | if (stack1.isFull() || maxLength == size()) { 19 | // 满了 20 | return false; 21 | } 22 | stack1.push(item); 23 | return true; 24 | } 25 | 26 | public int poll() { 27 | if (!stack2.isEmpty()) { 28 | return stack2.pop(); 29 | } else { 30 | while (!stack1.isEmpty()) { 31 | stack2.push(stack1.pop()); 32 | } 33 | return stack2.pop(); 34 | } 35 | } 36 | 37 | public int size() { 38 | return stack1.size() + stack2.size(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/extend/Stack2QueueTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02.extend; 2 | 3 | public class Stack2QueueTest { 4 | 5 | public static void main(String[] args) { 6 | Stack2Queue queue = new Stack2Queue(5); 7 | queue.put(1); 8 | queue.put(2); 9 | System.out.println(queue.poll()); // 1 10 | queue.put(3); 11 | queue.put(4); 12 | System.out.println(queue.poll()); // 2 13 | System.out.println(queue.poll()); // 3,本次会把3、4两个元素从stack1倒入stack2 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/extend/StaticLinkedList.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02.extend; 2 | 3 | public class StaticLinkedList { 4 | 5 | private Element[] elements; 6 | 7 | private int head; 8 | 9 | private int tail; 10 | 11 | private int unUsed; 12 | 13 | private int size; 14 | 15 | /** 16 | * 初始化操作 17 | * @param capacity 18 | */ 19 | public StaticLinkedList(int capacity) { 20 | elements = new Element[capacity]; 21 | unUsed = 0; 22 | for (int i = 0; i < capacity - 1; i++) { 23 | elements[i] = new Element(); 24 | elements[i].setCur(i + 1); 25 | } 26 | elements[capacity - 1] = new Element(); 27 | elements[capacity - 1].setCur(-1); 28 | } 29 | 30 | /** 31 | * 链表指定位置后面插入 32 | * @param data 要插入的值 33 | * @param index 链表位置(不是数组下标) 34 | */ 35 | public void insert(int data, int index) { 36 | if (index == 0) { 37 | insertFirst(data); 38 | } else if (index == size) { 39 | insertLast(data); 40 | } else { 41 | checkFull(); 42 | // 获取要插入元素的前一个元素 43 | Element preElement = get(index); 44 | // 获取一个未使用的元素作为要插入的元素 45 | Element unUsedElement = elements[unUsed]; 46 | // 记录要插入元素的数组下标 47 | int temp = unUsed; 48 | // 把从备用链表中拿出来的元素的下一个元素的数组下标设为备用链表头 49 | unUsed = unUsedElement.getCur(); 50 | // 把要插入元素的指针设为原本前一个元素的指针指向的下标值(链表插入操作) 51 | unUsedElement.setCur(preElement.getCur()); 52 | // 把前一个元素的指针指向插入的元素下标 53 | preElement.setCur(temp); 54 | // 赋值 55 | unUsedElement.setData(data); 56 | // 链表长度加1 57 | size ++; 58 | } 59 | } 60 | 61 | /** 62 | * 链表前端插入 63 | * @param data 64 | */ 65 | public void insertFirst(int data) { 66 | checkFull(); 67 | Element unUsedElement = elements[unUsed]; 68 | int temp = unUsed; 69 | unUsed = unUsedElement.getCur(); 70 | unUsedElement.setCur(head); 71 | unUsedElement.setData(data); 72 | head = temp; 73 | size ++; 74 | } 75 | 76 | /** 77 | * 链表尾插入 78 | * @param data 79 | */ 80 | public void insertLast(int data) { 81 | checkFull(); 82 | Element unUsedElement = elements[unUsed]; 83 | int temp = unUsed; 84 | unUsed = unUsedElement.getCur(); 85 | elements[tail].setCur(temp); 86 | unUsedElement.setData(data); 87 | tail = temp; 88 | size ++; 89 | } 90 | 91 | /** 92 | * 链表头删除 93 | */ 94 | public void deleteFirst() { 95 | checkEmpty(); 96 | Element deleteElement = elements[head]; 97 | int temp = head; 98 | head = deleteElement.getCur(); 99 | deleteElement.setCur(unUsed); 100 | unUsed = temp; 101 | size --; 102 | } 103 | 104 | /** 105 | * 链表尾删除 106 | */ 107 | public void deleteLast() { 108 | delete(size - 1); 109 | } 110 | 111 | /** 112 | * 删除指定位置元素 113 | * @param index 链表中的第几个元素(不是数组下标) 114 | */ 115 | public void delete(int index) { 116 | if (index == 0) { 117 | deleteFirst(); 118 | } else { 119 | checkEmpty(); 120 | Element pre = get(index - 1); 121 | int del = pre.getCur(); // 这个是数组的下标 122 | Element deleteElement = elements[del]; 123 | pre.setCur(deleteElement.getCur()); 124 | if (index == size - 1) { 125 | tail = index - 1; 126 | } 127 | deleteElement.setCur(unUsed); 128 | unUsed = del; 129 | size --; 130 | } 131 | } 132 | 133 | /** 134 | * 获取链表元素 135 | * @param index 链表的第几个元素(不是数组下标) 136 | * @return 137 | */ 138 | public Element get(int index) { 139 | checkEmpty(); 140 | Element element = elements[head]; 141 | for (int i = 0; i < index; i++) { 142 | element = elements[element.getCur()]; 143 | } 144 | return element; 145 | } 146 | 147 | /** 148 | * 顺序打印所有元素值 149 | */ 150 | public void printAll() { 151 | Element element = elements[head]; 152 | System.out.println(element.getData()); 153 | for (int i = 1; i < size; i++) { 154 | element = elements[element.getCur()]; 155 | System.out.println(element.getData()); 156 | } 157 | } 158 | 159 | public int size() { 160 | return size; 161 | } 162 | 163 | private void checkFull() { 164 | if (size == elements.length) { 165 | throw new IndexOutOfBoundsException("数组不够长了啊"); 166 | } 167 | } 168 | 169 | private void checkEmpty() { 170 | if (size == 0) { 171 | throw new IndexOutOfBoundsException("现在链表为空哦"); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch02/extend/StaticLinkedListTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch02.extend; 2 | 3 | public class StaticLinkedListTest { 4 | 5 | public static void main(String[] args) { 6 | StaticLinkedList link = new StaticLinkedList(10); 7 | link.insertFirst(2); 8 | link.insertFirst(1); 9 | link.insertLast(4); 10 | link.insertLast(5); 11 | link.insert(3, 1); // 在下标为1的元素之后插入元素 12 | link.printAll(); // 1,2,3,4,5 13 | link.deleteFirst(); 14 | link.deleteLast(); 15 | link.delete(1); 16 | link.printAll(); // 移除了头尾之后,剩下3个元素,移除下标为1的元素,只剩下两个元素2和4 17 | System.out.println(link.get(1).getData()); 18 | link.deleteFirst(); 19 | link.deleteFirst(); 20 | System.out.println(link.size());// 从头部全部移出 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch03/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch03; 2 | 3 | public class BubbleSort { 4 | 5 | private int[] array; 6 | 7 | public BubbleSort(int[] array) { 8 | this.array = array; 9 | } 10 | 11 | /** 12 | * 从小到大 13 | */ 14 | public void sort() { 15 | int length = array.length; 16 | if (length > 0) { 17 | for (int i = 1; i < length; i++) { 18 | for (int j = 0; j < length - i; j++) { 19 | if (array[j] > array[j + 1]) { 20 | int temp = array[j]; 21 | array[j] = array[j + 1]; 22 | array[j + 1] = temp; 23 | } 24 | } 25 | } 26 | } 27 | } 28 | 29 | /** 30 | * 从大到小 31 | */ 32 | public void sort2() { 33 | int length = array.length; 34 | if (length > 0) { 35 | for (int i = length - 1; i > 0; i--) { 36 | for (int j = length - 1; j > length - 1 - i ; j--) { 37 | if (array[j] > array[j - 1]) { 38 | int temp = array[j]; 39 | array[j] = array[j - 1]; 40 | array[j - 1] = temp; 41 | } 42 | } 43 | } 44 | } 45 | } 46 | 47 | public void print() { 48 | for (int i = 0; i < array.length; i++) { 49 | System.out.println(array[i]); 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch03/BucketSort.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch03; 2 | 3 | public class BucketSort { 4 | 5 | private int[] buckets; 6 | private int[] array; 7 | 8 | public BucketSort(int range, int[] array) { 9 | this.buckets = new int[range]; 10 | this.array = array; 11 | } 12 | 13 | /** 14 | * 排序 15 | */ 16 | public void sort() { 17 | if (array != null && array.length > 1) { 18 | for (int i = 0; i < array.length; i++) { 19 | buckets[array[i]] ++; 20 | } 21 | } 22 | } 23 | 24 | /** 25 | * 从大到小排序 26 | */ 27 | public void print() { 28 | // 倒序输出数据 29 | for (int i = buckets.length - 1; i >= 0; i--) { 30 | // 元素中值为几,说明有多少个相同值的元素,则输出几遍 31 | for (int j = 0; j < buckets[i]; j ++) { 32 | System.out.println(i); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch03/InsertSort.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch03; 2 | 3 | public class InsertSort { 4 | 5 | private int[] array; 6 | 7 | public InsertSort(int[] array) { 8 | this.array = array; 9 | } 10 | 11 | public void sort() { 12 | if (array == null) { 13 | throw new RuntimeException("array is null"); 14 | } 15 | int length = array.length; 16 | if (length > 0) { 17 | for (int i = 1; i < length; i++) { 18 | int temp = array[i]; 19 | int j = i; 20 | for (; j > 0 && array[j - 1] > temp; j--) { 21 | array[j] = array[j - 1]; 22 | } 23 | array[j] = temp; 24 | } 25 | } 26 | } 27 | 28 | public void print() { 29 | for (int i = 0; i < array.length; i++) { 30 | System.out.println(array[i]); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch03/QuickSort.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch03; 2 | 3 | public class QuickSort { 4 | 5 | private int[] array; 6 | 7 | public QuickSort(int[] array) { 8 | this.array = array; 9 | } 10 | 11 | public void sort() { 12 | quickSort(array, 0, array.length - 1); 13 | } 14 | 15 | public void print() { 16 | for (int i = 0; i < array.length; i++) { 17 | System.out.println(array[i]); 18 | } 19 | } 20 | 21 | /** 22 | * 递归排序 23 | * @param src 24 | * @param begin 25 | * @param end 26 | */ 27 | private void quickSort(int[] src, int begin, int end) { 28 | if (begin < end) { 29 | int key = src[begin]; 30 | int i = begin; 31 | int j = end; 32 | 33 | while (i < j) { 34 | while (i < j && src[j] > key) { 35 | j--; 36 | } 37 | if (i < j) { 38 | src[i] = src[j]; 39 | i++; 40 | } 41 | while (i < j && src[i] < key) { 42 | i++; 43 | } 44 | if (i < j) { 45 | src[j] = src[i]; 46 | j--; 47 | } 48 | } 49 | 50 | src[i] = key; 51 | 52 | quickSort(src, begin, i - 1); 53 | quickSort(src, i + 1, end); 54 | } 55 | 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch03/SelectSort.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch03; 2 | 3 | public class SelectSort { 4 | 5 | private int[] array; 6 | 7 | public SelectSort(int[] array) { 8 | this.array = array; 9 | } 10 | 11 | public void sort() { 12 | int length = array.length; 13 | for (int i = 0; i < length; i++) { 14 | int minIndex = i; 15 | 16 | for (int j = i + 1; j < array.length; j++) { 17 | if (array[j] < array[minIndex]) { 18 | minIndex = j; 19 | } 20 | } 21 | 22 | if (minIndex != i) { 23 | int temp = array[minIndex]; 24 | array[minIndex] = array[i]; 25 | array[i] = temp; 26 | } 27 | } 28 | } 29 | 30 | public void print() { 31 | for (int i = 0; i < array.length; i++) { 32 | System.out.println(array[i]); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch03/ShellSort.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch03; 2 | 3 | public class ShellSort { 4 | 5 | private int[] array; 6 | 7 | public ShellSort(int[] array) { 8 | this.array = array; 9 | } 10 | 11 | public void sort() { 12 | int temp; 13 | for (int k = array.length / 2; k > 0; k /= 2) { 14 | for (int i = k; i < array.length; i++) { 15 | for (int j = i; j >= k; j -= k) { 16 | if (array[j - k] > array[j]) { 17 | temp = array[j - k]; 18 | array[j - k] = array[j]; 19 | array[j] = temp; 20 | } 21 | } 22 | } 23 | } 24 | } 25 | 26 | public void print() { 27 | for (int i = 0; i < array.length; i++) { 28 | System.out.println(array[i]); 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch03/SortTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch03; 2 | 3 | public class SortTest { 4 | 5 | public static void main(String[] args) { 6 | // testBucketSort(); 7 | // testBubbleSort(); 8 | // testQuickSort(); 9 | // testInsertSort(); 10 | // testShellSort(); 11 | testSelectSort(); 12 | } 13 | 14 | /** 15 | * 桶排序 16 | */ 17 | private static void testBucketSort() { 18 | int[] array = {5, 9, 1, 9, 5, 3, 7, 6, 1}; 19 | BucketSort bucketSort = new BucketSort(11, array); 20 | bucketSort.sort(); 21 | bucketSort.print(); 22 | } 23 | 24 | /** 25 | * 冒泡排序 26 | */ 27 | private static void testBubbleSort() { 28 | int[] array = {5, 9, 1, 9, 5, 3, 7, 6, 1}; 29 | BubbleSort bubbleSort = new BubbleSort(array); 30 | bubbleSort.sort2(); 31 | bubbleSort.print(); 32 | } 33 | 34 | /** 35 | * 快速排序 36 | */ 37 | private static void testQuickSort() { 38 | int[] array = {5, 9, 1, 9, 5, 3, 7, 6, 1}; 39 | QuickSort quickSort = new QuickSort(array); 40 | quickSort.sort(); 41 | quickSort.print(); 42 | } 43 | 44 | /** 45 | * 插入排序 46 | */ 47 | private static void testInsertSort() { 48 | int[] array = {5, 9, 1, 9, 5, 3, 7, 6, 1}; 49 | InsertSort insertSort = new InsertSort(array); 50 | insertSort.sort(); 51 | insertSort.print(); 52 | } 53 | 54 | /** 55 | * 希尔排序 56 | */ 57 | private static void testShellSort() { 58 | int[] array = {5, 9, 1, 9, 5, 3, 7, 6, 1}; 59 | ShellSort shellSort = new ShellSort(array); 60 | shellSort.sort(); 61 | shellSort.print(); 62 | } 63 | 64 | /** 65 | * 简单选择排序 66 | */ 67 | private static void testSelectSort() { 68 | int[] array = {5, 9, 1, 9, 5, 3, 7, 6, 1}; 69 | SelectSort selectSort = new SelectSort(array); 70 | selectSort.sort(); 71 | selectSort.print(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch04/BinarySearch.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch04; 2 | 3 | public class BinarySearch { 4 | 5 | private int[] array; 6 | 7 | /** 8 | * 初始化数组 9 | * @param array 10 | */ 11 | public BinarySearch(int[] array) { 12 | this.array = array; 13 | } 14 | 15 | /** 16 | * 二分查找 17 | * @param target 18 | * @return 19 | */ 20 | public int search(int target) { 21 | if (array == null) { 22 | return -1; 23 | } 24 | 25 | int start = 0; 26 | int end = array.length - 1; 27 | 28 | while (start <= end) { 29 | int mid = start + (end - start) / 2; 30 | if (array[mid] == target) { 31 | return mid; 32 | } else if (target < array[mid]) { 33 | end = mid - 1; 34 | } else { 35 | start = mid + 1; 36 | } 37 | } 38 | return -1; 39 | } 40 | 41 | /** 42 | * 递归实现二分查找 43 | * @param target 44 | * @return 45 | */ 46 | public int searchRecursion(int target) { 47 | if (array != null) { 48 | return searchRecursion(target, 0, array.length - 1); 49 | } 50 | return -1; 51 | } 52 | 53 | private int searchRecursion(int target, int start, int end) { 54 | if (start > end) { 55 | return -1; 56 | } 57 | int mid = start + (end - start) / 2; 58 | if (array[mid] == target) { 59 | return mid; 60 | } else if (target < array[mid]) { 61 | return searchRecursion(target, start, mid - 1); 62 | } else { 63 | return searchRecursion(target, mid + 1, end); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch04/BinarySearchTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch04; 2 | 3 | public class BinarySearchTest { 4 | 5 | public static void main(String[] args) { 6 | int[] array = new int[]{1, 3, 5, 7, 9, 11, 19}; 7 | BinarySearch binarySearch = new BinarySearch(array); 8 | System.out.println(binarySearch.search(0)); 9 | System.out.println(binarySearch.search(11)); 10 | System.out.println(binarySearch.searchRecursion(0)); 11 | System.out.println(binarySearch.searchRecursion(11)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch04/BinarySort.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch04; 2 | 3 | public class BinarySort { 4 | 5 | private int[] array; 6 | 7 | public BinarySort(int[] array) { 8 | this.array = array; 9 | } 10 | 11 | public void sort() { 12 | if (array == null) { 13 | throw new RuntimeException("array is null"); 14 | } 15 | if (array.length > 0) { 16 | for (int i = 1; i < array.length; i++) { 17 | int temp = array[i]; 18 | // 二分查找插入位置 19 | int insertIndex = binarySearch(i - 1, temp); 20 | if (i != insertIndex) { 21 | // 移动需要移动的元素 22 | for (int j = i - 1; j >= insertIndex; j --) { 23 | array[j] = array[j - 1]; 24 | } 25 | // 插入元素 26 | array[insertIndex] = temp; 27 | } 28 | } 29 | } 30 | } 31 | 32 | public void print() { 33 | for (int i = 0; i < array.length; i++) { 34 | System.out.println(array[i]); 35 | } 36 | } 37 | 38 | /** 39 | * 二分查找定位插入索引 40 | * @param maxIndex 有序区最大索引 41 | * @param data 要找的值 42 | * @return 43 | */ 44 | private int binarySearch(int maxIndex, int data) { 45 | int start = 0; 46 | int end = maxIndex; 47 | int mid = -1; 48 | while (start <= end) { 49 | mid = (start + end) / 2; 50 | if (array[mid] > data) { 51 | end = mid - 1; 52 | } else { 53 | // 如果相等,也插入在后面 54 | start = mid + 1; 55 | } 56 | } 57 | return start; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch04/BlockSearch.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch04; 2 | 3 | import me.irfen.algorithm.ch01.ArrayList; 4 | 5 | public class BlockSearch { 6 | 7 | private int[] index; 8 | 9 | private ArrayList[] list; 10 | 11 | /** 12 | * 初始化索引表 13 | * @param index 14 | */ 15 | public BlockSearch(int[] index) { 16 | if (index != null && index.length != 0) { 17 | this.index = index; 18 | this.list = new ArrayList[index.length]; 19 | for (int i = 0; i < list.length; i++) { 20 | list[i] = new ArrayList(); 21 | } 22 | } else { 23 | throw new Error("index cannot be null or empty."); 24 | } 25 | } 26 | 27 | /** 28 | * 插入元素 29 | * @param value 30 | */ 31 | public void insert(int value) { 32 | int i = binarySearch(value); 33 | list[i].add(value); 34 | } 35 | 36 | /** 37 | * 查找元素 38 | * @param data 39 | * @return 40 | */ 41 | public boolean search(int data) { 42 | int i = binarySearch(data); 43 | for (int j = 0; j < list[i].size(); j++) { 44 | if (data == list[i].get(j)) { 45 | return true; 46 | } 47 | } 48 | return false; 49 | } 50 | 51 | /** 52 | * 打印每块元素 53 | */ 54 | public void printAll() { 55 | for (int i = 0; i < list.length; i++) { 56 | ArrayList l = list[i]; 57 | System.out.println("ArrayList " + i + ":"); 58 | for (int j = 0; j < l.size(); j++) { 59 | System.out.println(l.get(j)); 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * 二分查找定位索引位置 66 | * @param data 要插入的值 67 | * @return 68 | */ 69 | private int binarySearch(int data) { 70 | int start = 0; 71 | int end = index.length; 72 | int mid = -1; 73 | while (start <= end) { 74 | mid = (start + end) / 2; 75 | if (index[mid] > data) { 76 | end = mid - 1; 77 | } else { 78 | // 如果相等,也插入在后面 79 | start = mid + 1; 80 | } 81 | } 82 | return start; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch04/BlockSearchTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch04; 2 | 3 | public class BlockSearchTest { 4 | 5 | public static void main(String[] args) { 6 | int[] index = {10, 20, 30}; 7 | BlockSearch blockSearch = new BlockSearch(index); 8 | 9 | blockSearch.insert(1); 10 | blockSearch.insert(12); 11 | blockSearch.insert(22); 12 | 13 | blockSearch.insert(9); 14 | blockSearch.insert(18); 15 | blockSearch.insert(23); 16 | 17 | blockSearch.insert(5); 18 | blockSearch.insert(15); 19 | blockSearch.insert(27); 20 | 21 | blockSearch.printAll(); 22 | 23 | System.out.println(blockSearch.search(18)); 24 | System.out.println(blockSearch.search(29)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch04/SequentialSearch.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch04; 2 | 3 | public class SequentialSearch { 4 | 5 | private int[] array; 6 | 7 | public SequentialSearch(int[] array) { 8 | this.array = array; 9 | } 10 | 11 | /** 12 | * 直接顺序查找 13 | * @param key 14 | * @return 15 | */ 16 | public int search(int key) { 17 | for (int i = 0; i < array.length; i++) { 18 | if (array[i] == key) { 19 | return i; 20 | } 21 | } 22 | return -1; 23 | } 24 | 25 | /** 26 | * 哨兵方式顺序查找 27 | * @param key 28 | * @return 29 | */ 30 | public int search2(int key) { 31 | // 先判断是否等于下标为0的元素 32 | if (key == array[0]) { 33 | return 0; 34 | } 35 | // 临时保存array[0]的值 36 | int temp = array[0]; 37 | // 赋值给下标为0的元素 38 | array[0] = key; 39 | int i = array.length - 1; 40 | // 倒序比较 41 | while(array[i] != key) { 42 | i --; 43 | } 44 | // 把array[0]原本的值赋回去 45 | array[0] = temp; 46 | // 比较到最后了也没有找到返回-1 47 | if (i == 0) { 48 | return -1; 49 | } 50 | // 找到了的话返回数组下标 51 | return i; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch04/YoungSearch.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch04; 2 | 3 | public class YoungSearch { 4 | 5 | private int[][] array; 6 | 7 | public YoungSearch(int[][] array) { 8 | this.array = array; 9 | } 10 | 11 | /** 12 | * 递归实现 13 | * @param x 14 | * @param y 15 | * @param target 16 | * @return 17 | */ 18 | public boolean recursionSearch(int x, int y, int target) { 19 | if (x == array.length || y == array[0].length) { 20 | return false; 21 | } 22 | if (target < array[x][y]) { 23 | return false; 24 | } 25 | if (target == array[x][y]) { 26 | System.out.println(String.format("x: %d, y: %d", x, y)); 27 | return true; 28 | } 29 | return recursionSearch(x + 1, y, target) || recursionSearch(x, y + 1, target); 30 | } 31 | 32 | /** 33 | * 直接查找 34 | * @param target 35 | * @return 36 | */ 37 | public boolean search(int target) { 38 | for (int i = 0; i < array.length; i++) { 39 | for (int j = 0; target >= array[i][j] && j < array[0].length; j++) { 40 | if (target == array[i][j]) { 41 | System.out.println(String.format("x: %d, y: %d", i, j)); 42 | return true; 43 | } else if (target < array[i][j]) { 44 | return false; 45 | } 46 | } 47 | } 48 | return false; 49 | } 50 | 51 | /** 52 | * 优化的查找 53 | * @param target 54 | * @return 55 | */ 56 | public boolean search2(int target) { 57 | int width = array[0].length; 58 | int height = array.length; 59 | if (target >= array[0][0]) { 60 | int i = 0; 61 | // 先从头开始第一行的查找 62 | for (; target >=array[0][i] && i < width - 1; i++) { 63 | if (target == array[0][i]) { 64 | System.out.println(String.format("x: %d, y: %d", 0, i)); 65 | return true; 66 | } 67 | } 68 | // 该行未找到,修复i为矩阵范围内数值 69 | if (i > width - 1) { 70 | i--; 71 | } 72 | // 开始循环向下寻找 73 | for (int j = 1; j < height; j++) { 74 | if (array[j][i] == target) { 75 | System.out.println(String.format("x: %d, y: %d", j, i)); 76 | return true; 77 | } else if (array[j][i] > target) { 78 | for (; i >= 0; i--) { 79 | if (array[j][i] == target) { 80 | System.out.println(String.format("x: %d, y: %d", j, i)); 81 | return true; 82 | } else if (array[j][i] <= target) { 83 | break; 84 | } 85 | } 86 | // 该行未找到,修复i为矩阵范围内数值 87 | if (i < 0) { 88 | i++; 89 | } 90 | } else if (array[j][i] < target) { 91 | for (; i < width - 1; i++) { 92 | if (array[j][i] == target) { 93 | System.out.println(String.format("x: %d, y: %d", j, i)); 94 | return true; 95 | } else if (array[j][i] >= target) { 96 | break; 97 | } 98 | } 99 | // 该行未找到,修复i为矩阵范围内数值 100 | if (i > width - 1) { 101 | i--; 102 | } 103 | } 104 | } 105 | } 106 | return false; 107 | } 108 | 109 | /** 110 | * 定位查找 111 | * @param target 112 | * @return 113 | */ 114 | public boolean search3(int target) { 115 | int i = 0, j = array[0].length - 1; 116 | int temp = array[i][j]; 117 | while (true){ 118 | if (temp == target) { 119 | System.out.println(String.format("x: %d, y: %d", i, j)); 120 | return true; 121 | } else if (temp < target && i < array.length - 1) { 122 | temp = array[++i][j]; 123 | } else if (temp > target && j > 0) { 124 | temp = array[i][--j]; 125 | } else { 126 | // 最终没找到 127 | return false; 128 | } 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch04/YoungSearchTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch04; 2 | 3 | public class YoungSearchTest { 4 | 5 | public static void main(String[] args) { 6 | int[][] array = {{1, 2, 8, 9, 15, 22, 38}, 7 | {2, 5, 9, 12, 16, 25, 42}, 8 | {4, 7, 13, 15, 21, 28, 46}, 9 | {7, 9, 16, 18, 24, 32, 52}}; 10 | YoungSearch youngSearch = new YoungSearch(array); 11 | System.out.println("递归查找:"); 12 | System.out.println(youngSearch.recursionSearch(0, 0, 13)); 13 | System.out.println(youngSearch.recursionSearch(0, 0, 20)); 14 | 15 | System.out.println("直接查找:"); 16 | System.out.println(youngSearch.search(13)); 17 | System.out.println(youngSearch.search(20)); 18 | 19 | System.out.println("优化查找:"); 20 | System.out.println(youngSearch.search2(13)); 21 | System.out.println(youngSearch.search2(20)); 22 | System.out.println(youngSearch.search2(46)); 23 | System.out.println(youngSearch.search2(4)); 24 | System.out.println(youngSearch.search2(99)); 25 | 26 | System.out.println("定位查找"); 27 | System.out.println(youngSearch.search3(13)); 28 | System.out.println(youngSearch.search3(20)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch05/BinarySearchingTree.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch05; 2 | 3 | public class BinarySearchingTree { 4 | 5 | private BinaryTreeNode root; 6 | 7 | public BinarySearchingTree(BinaryTreeNode root) { 8 | this.root = root; 9 | } 10 | 11 | public void insert(int data) { 12 | if (root == null) { 13 | root = new BinaryTreeNode(); 14 | root.setData(data); 15 | } else { 16 | searchAndInsert(null, root, data); 17 | } 18 | } 19 | 20 | /** 21 | * 中根遍历 22 | * @param node 23 | */ 24 | public void inOrder(BinaryTreeNode node) { 25 | if (node != null) { 26 | inOrder(node.getLeftChild()); 27 | visted(node); 28 | inOrder(node.getRightChild()); 29 | } 30 | } 31 | private void visted(BinaryTreeNode node) { 32 | System.out.println(node.getData()); 33 | } 34 | 35 | public void delete(int data) { 36 | // 根节点直接赋值为空 37 | if (root.getData() == data) { 38 | root = null; 39 | return; 40 | } 41 | // 整个过程都需要知道父节点,因为Java是引用传递不能直接赋值 42 | // C语言可以用指针 43 | BinaryTreeNode parent = searchParent(data); 44 | if (parent == null) { 45 | return; 46 | } 47 | BinaryTreeNode node = search(parent, data); 48 | if (node.getLeftChild() == null && node.getRightChild() == null) { 49 | // 叶子节点直接删除 50 | if (parent.getLeftChild() != null && parent.getLeftChild().getData() == data) { 51 | parent.setLeftChild(null); 52 | } else { 53 | parent.setRightChild(null); 54 | } 55 | } else if (node.getLeftChild() != null && node.getRightChild() == null) { 56 | // 左子树不为空树 57 | if (parent.getLeftChild() != null && parent.getLeftChild().getData() == data) { 58 | parent.setLeftChild(node.getLeftChild()); 59 | } else { 60 | parent.setRightChild(node.getLeftChild()); 61 | } 62 | } else if (node.getLeftChild() == null && node.getRightChild() != null) { 63 | // 右子树不为空树 64 | if (parent.getLeftChild() != null && parent.getLeftChild().getData() == data) { 65 | parent.setLeftChild(node.getRightChild()); 66 | } else { 67 | parent.setRightChild(node.getRightChild()); 68 | } 69 | } else { 70 | // 左右子树都不为空树 71 | // 1. 查找右子树中最左子节点 72 | BinaryTreeNode deleteNode = node; // 要删除的节点 73 | BinaryTreeNode temp = node.getRightChild(); // 要删除节点的右子树树根 74 | if (temp.getLeftChild() == null) { 75 | // 如果右子树没有左孩子,直接上移 76 | temp.setLeftChild(deleteNode.getLeftChild()); 77 | } else { 78 | // 右子树的左孩子不为空 79 | while (temp.getLeftChild() != null) { 80 | node = temp; 81 | temp = temp.getLeftChild(); 82 | } 83 | // 2.继承节点原右子树上移 84 | node.setLeftChild(temp.getRightChild()); 85 | // 3.继承节点就位 86 | temp.setLeftChild(deleteNode.getLeftChild()); 87 | temp.setRightChild(deleteNode.getRightChild()); 88 | } 89 | // 4.更新父节点为删除节点的原父节点 90 | if (parent.getLeftChild() != null && parent.getLeftChild().getData() == data) { 91 | parent.setLeftChild(temp); 92 | } else { 93 | parent.setRightChild(temp); 94 | } 95 | } 96 | } 97 | 98 | /** 99 | * 二叉查找树查找父节点 100 | * @param data 101 | * @return 102 | */ 103 | public BinaryTreeNode searchParent(int data) { 104 | return searchParent(null, root, data); 105 | } 106 | 107 | /** 108 | * 二叉查找树的查找 109 | * @param data 110 | * @return 111 | */ 112 | public BinaryTreeNode search(int data) { 113 | return search(root, data); 114 | } 115 | 116 | /** 117 | * 递归二叉查找树 118 | * @param node 119 | * @param data 120 | * @return 121 | */ 122 | private BinaryTreeNode search(BinaryTreeNode node, int data) { 123 | if (node == null) { 124 | return null; 125 | } else if (node.getData() == data) { 126 | return node; 127 | } else if (data > node.getData()) { 128 | return search(node.getRightChild(), data); 129 | } else { 130 | return search(node.getLeftChild(), data); 131 | } 132 | } 133 | 134 | /** 135 | * 递归二叉查找树 136 | * @param node 137 | * @param data 138 | * @return 139 | */ 140 | private BinaryTreeNode searchParent(BinaryTreeNode parent, BinaryTreeNode node, int data) { 141 | if (node == null) { 142 | return null; 143 | } else if (node.getData() == data) { 144 | return parent; 145 | } else if (data > node.getData()) { 146 | return searchParent(node, node.getRightChild(), data); 147 | } else { 148 | return searchParent(node, node.getLeftChild(), data); 149 | } 150 | } 151 | 152 | /** 153 | * 递归二叉查找树(如果没有找到,就新建一个最终位置的节点) 154 | * @param parent 155 | * @param node 156 | * @param data 157 | * @return 158 | */ 159 | private BinaryTreeNode searchAndInsert(BinaryTreeNode parent, BinaryTreeNode node, int data) { 160 | if (node == null) { 161 | node = new BinaryTreeNode(); 162 | node.setData(data); 163 | if (data > parent.getData()) { 164 | parent.setRightChild(node); 165 | } else { 166 | parent.setLeftChild(node); 167 | } 168 | return node; 169 | } else if (node.getData() == data) { 170 | return node; 171 | } else if (data > node.getData()) { 172 | return searchAndInsert(node, node.getRightChild(), data); 173 | } else { 174 | return searchAndInsert(node, node.getLeftChild(), data); 175 | } 176 | } 177 | 178 | public BinaryTreeNode getRoot() { 179 | return root; 180 | } 181 | 182 | } 183 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch05/BinaryTree.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch05; 2 | 3 | public class BinaryTree { 4 | 5 | private BinaryTreeNode root; 6 | 7 | public BinaryTree() { 8 | } 9 | 10 | public BinaryTree(BinaryTreeNode root) { 11 | this.root = root; 12 | } 13 | 14 | /** 15 | * 给某节点插入左子节点 16 | * @param parent 17 | * @param newNode 18 | */ 19 | public void insertLeft(BinaryTreeNode parent, BinaryTreeNode newNode) { 20 | parent.setLeftChild(newNode); 21 | } 22 | 23 | /** 24 | * 给某节点插入右子节点 25 | * @param parent 26 | * @param newNode 27 | */ 28 | public void insertRight(BinaryTreeNode parent, BinaryTreeNode newNode) { 29 | parent.setRightChild(newNode); 30 | } 31 | 32 | 33 | /** 34 | * 查找node节点在二叉树中的父节点 35 | * @param node 36 | * @return 37 | */ 38 | public BinaryTreeNode getParent(BinaryTreeNode node) { 39 | return (root == null || root == node) ? null : getParent(root, node); 40 | } 41 | 42 | /** 43 | * 递归查找node节点在subTree子树中的父节点 44 | * @param subTree 45 | * @param node 46 | * @return 47 | */ 48 | public BinaryTreeNode getParent(BinaryTreeNode subTree, BinaryTreeNode node) { 49 | if (subTree == null) { 50 | // 如果子树为空,则没有父节点 51 | return null; 52 | } 53 | if (subTree.getLeftChild() == node || subTree.getRightChild() == node) { 54 | // 如果子树树根的左右孩子节点之一是待查节点,那么这个子树树根即为待查节点的父节点 55 | return subTree; 56 | } 57 | BinaryTreeNode parent = null; 58 | // 先递归在左子树找 59 | if ((parent = getParent(subTree.getLeftChild(), node)) != null) { 60 | return parent; 61 | } else { 62 | // 递归在右子树找 63 | return getParent(subTree.getRightChild(), node); 64 | } 65 | } 66 | 67 | /** 68 | * 获取某个节点的左子树 69 | * @param node 70 | * @return 71 | */ 72 | public BinaryTreeNode getLeftTree(BinaryTreeNode node) { 73 | return node.getLeftChild(); 74 | } 75 | 76 | /** 77 | * 获取某个节点的右子树 78 | * @param node 79 | * @return 80 | */ 81 | public BinaryTreeNode getRightTree(BinaryTreeNode node) { 82 | return node.getRightChild(); 83 | } 84 | 85 | /** 86 | * 获取二叉树的节点个数 87 | * @return 88 | */ 89 | public int size() { 90 | return size(root); 91 | } 92 | 93 | /** 94 | * 获取某节点为子树的节点个数 95 | * @param node 96 | * @return 97 | */ 98 | public int size(BinaryTreeNode node) { 99 | if (node == null) { 100 | // 如果节点为空,返回节点个数为0 101 | return 0; 102 | } else { 103 | // 需要计算本节点,所以加1 104 | // 递归获取左子树的节点个数及右子树的节点个数,最终相加 105 | return 1 + size(node.getLeftChild()) + size(node.getRightChild()); 106 | } 107 | } 108 | 109 | /** 110 | * 获取二叉树高度 111 | * @return 112 | */ 113 | public int height() { 114 | return height(root); 115 | } 116 | 117 | /** 118 | * 获取某节点为子树的高度 119 | * @param node 120 | * @return 121 | */ 122 | public int height(BinaryTreeNode node) { 123 | if (node == null) { 124 | return 0; // 递归结束,空子树高度为0 125 | } else { 126 | // 递归获取左子树高度 127 | int l = height(node.getLeftChild()); 128 | // 递归获取右子树高度 129 | int r = height(node.getRightChild()); 130 | // 高度应该算更高的那一边(加1是因为要加上自己这一层) 131 | return l < r ? r + 1 : l + 1; 132 | } 133 | } 134 | 135 | /** 136 | * 判断二叉树树是否为空 137 | * @return 138 | */ 139 | public boolean isEmpty() { 140 | return root == null; 141 | } 142 | 143 | /** 144 | * 清空树 145 | */ 146 | public void clear() { 147 | root = null; 148 | } 149 | 150 | /** 151 | * 先根遍历 152 | * @param node 153 | */ 154 | public void preOrder(BinaryTreeNode node) { 155 | if (node != null) { 156 | visted(node); 157 | preOrder(node.getLeftChild()); 158 | preOrder(node.getRightChild()); 159 | } 160 | } 161 | 162 | /** 163 | * 中根遍历 164 | * @param node 165 | */ 166 | public void inOrder(BinaryTreeNode node) { 167 | if (node != null) { 168 | inOrder(node.getLeftChild()); 169 | visted(node); 170 | inOrder(node.getRightChild()); 171 | } 172 | } 173 | 174 | /** 175 | * 后根遍历 176 | * @param node 177 | */ 178 | public void postOrder(BinaryTreeNode node) { 179 | if (node != null) { 180 | postOrder(node.getLeftChild()); 181 | postOrder(node.getRightChild()); 182 | visted(node); 183 | } 184 | } 185 | 186 | public void setRoot(BinaryTreeNode root) { 187 | this.root = root; 188 | } 189 | 190 | public BinaryTreeNode getRoot() { 191 | return root; 192 | } 193 | 194 | private void visted(BinaryTreeNode node) { 195 | System.out.println(node.getData()); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch05/BinaryTreeNode.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch05; 2 | 3 | public class BinaryTreeNode { 4 | 5 | private int data; // 数据 6 | private BinaryTreeNode leftChild; // 左孩子 7 | private BinaryTreeNode rightChild; // 右孩子 8 | 9 | public int getData() { 10 | return data; 11 | } 12 | public void setData(int data) { 13 | this.data = data; 14 | } 15 | public BinaryTreeNode getLeftChild() { 16 | return leftChild; 17 | } 18 | public void setLeftChild(BinaryTreeNode leftChild) { 19 | this.leftChild = leftChild; 20 | } 21 | public BinaryTreeNode getRightChild() { 22 | return rightChild; 23 | } 24 | public void setRightChild(BinaryTreeNode rightChild) { 25 | this.rightChild = rightChild; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch05/BinaryTreeNode2.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch05; 2 | 3 | public class BinaryTreeNode2 { 4 | 5 | private int leftChild; 6 | private int rightChild; 7 | 8 | public int getLeftChild() { 9 | return leftChild; 10 | } 11 | public void setLeftChild(int leftChild) { 12 | this.leftChild = leftChild; 13 | } 14 | public int getRightChild() { 15 | return rightChild; 16 | } 17 | public void setRightChild(int rightChild) { 18 | this.rightChild = rightChild; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch05/Heap.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch05; 2 | 3 | public class Heap { 4 | 5 | private int[] element; 6 | 7 | public Heap(int maxSize) { 8 | element = new int[maxSize + 1]; 9 | element[0] = 0; // 其实Java默认会赋值数组所有值为0的 10 | } 11 | 12 | /** 13 | * 大顶堆添加元素 14 | * @param value 15 | */ 16 | public void insert(int value) { 17 | if (isFull()) { 18 | throw new IndexOutOfBoundsException("大顶堆已经满啦"); 19 | } 20 | if (isEmpty()) { 21 | element[1] = value; 22 | } else { 23 | int i = element[0] + 1; // 确认新增元素下标 24 | while (i != 1 && value > element[i / 2]) { 25 | // 如果比父节点值大,父节点值下移 26 | element[i] = element[i / 2]; 27 | i /= 2; 28 | } 29 | // 最终把值插入到指定位置 30 | element[i] = value; 31 | } 32 | element[0] ++; 33 | } 34 | 35 | /** 36 | * 删除大顶堆根节点元素 37 | */ 38 | public int delete() { 39 | if (isEmpty()) { 40 | throw new IndexOutOfBoundsException("大顶堆已经空啦"); 41 | } 42 | // 删除元素,先赋值为最后一个有效元素 43 | int deleteElement = element[1]; 44 | element[1] = element[element[0]]; 45 | element[0] --; 46 | int temp = element[1]; 47 | // 重建堆 48 | int parent = 1; 49 | int child = 2; 50 | // 循环至叶子节点 51 | while (child <= element[0]) { 52 | if (child < element[0] && element[child] < element[child + 1]) { 53 | // 首先要确保child+1之后不能越界, 54 | // 接着如果左孩子的值小于右孩子的值,那就选择使用右孩子进行比较交换 55 | child ++; 56 | } 57 | if (temp > element[child]) { 58 | break; 59 | } else { 60 | element[parent] = element[child]; 61 | parent = child; 62 | child *= 2; 63 | } 64 | } 65 | // 把最后一个有效元素放到该放的位置 66 | element[parent] = temp; 67 | return deleteElement; 68 | } 69 | 70 | public void sort() { 71 | // 首先需要初始化元素 72 | if (isEmpty()) { 73 | throw new RuntimeException("先给初始化点数据来排序呗"); 74 | } 75 | // 依次删除元素,放入数组最后 76 | int size = element[0]; 77 | for (int i = 0; i < size; i++) { 78 | int deleteElement = delete(); 79 | element[element[0] + 1] = deleteElement; 80 | } 81 | // 输出排序后元素 82 | for (int i = 1; i < size + 1; i++) { 83 | System.out.print(element[i]); 84 | if (i != size) { 85 | System.out.print(","); 86 | } 87 | } 88 | } 89 | 90 | public boolean isFull() { 91 | return element[0] == element.length - 1; 92 | } 93 | 94 | public boolean isEmpty() { 95 | return element[0] == 0; 96 | } 97 | 98 | public void printAll() { 99 | for (int i = 1; i < element[0] + 1; i++) { 100 | System.out.print(element[i]); 101 | if (i != element[0]) { 102 | System.out.print(","); 103 | } 104 | } 105 | System.out.println(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch05/HeapSortTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch05; 2 | 3 | public class HeapSortTest { 4 | 5 | public static void main(String[] args) { 6 | // 1.构建堆 7 | Heap heap = new Heap(100); 8 | // 2.依次添加元素 9 | int[] array = {9, 18, 34, 15, 29, 66, 12, 48}; 10 | for (int i = 0; i < array.length; i++) { 11 | heap.insert(array[i]); 12 | } 13 | // 3.排序并输出排序后元素 14 | heap.sort(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch05/HeapTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch05; 2 | 3 | public class HeapTest { 4 | 5 | public static void main(String[] args) { 6 | Heap heap = new Heap(100); 7 | heap.insert(9); 8 | heap.insert(18); 9 | heap.insert(34); 10 | heap.insert(15); 11 | heap.insert(29); 12 | heap.insert(66); 13 | heap.insert(12); 14 | heap.insert(48); 15 | 16 | heap.printAll(); 17 | 18 | heap.delete(); 19 | heap.printAll(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch05/Test.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch05; 2 | 3 | public class Test { 4 | 5 | public static void main(String[] args) { 6 | BinarySearchingTree tree = new BinarySearchingTree(null); 7 | tree.insert(42); 8 | tree.insert(14); 9 | tree.insert(65); 10 | tree.insert(9); 11 | tree.insert(23); 12 | tree.insert(55); 13 | tree.insert(72); 14 | tree.insert(1); 15 | tree.insert(68); 16 | tree.insert(88); 17 | tree.insert(70); 18 | 19 | System.out.println(tree.search(9).getData()); 20 | System.out.println(tree.search(1).getData()); 21 | System.out.println(tree.search(24)); 22 | 23 | tree.delete(65); 24 | 25 | tree.inOrder(tree.getRoot()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch05/TreeNode1.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch05; 2 | 3 | public class TreeNode1 { 4 | 5 | private int data; 6 | private int parent; 7 | 8 | public int getData() { 9 | return data; 10 | } 11 | public void setData(int data) { 12 | this.data = data; 13 | } 14 | public int getParent() { 15 | return parent; 16 | } 17 | public void setParent(int parent) { 18 | this.parent = parent; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch05/TreeNode2.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch05; 2 | 3 | import me.irfen.algorithm.ch02.Link; 4 | 5 | public class TreeNode2 { 6 | 7 | private int data; 8 | private int parent; 9 | private Link children; 10 | 11 | public int getData() { 12 | return data; 13 | } 14 | public void setData(int data) { 15 | this.data = data; 16 | } 17 | public int getParent() { 18 | return parent; 19 | } 20 | public void setParent(int parent) { 21 | this.parent = parent; 22 | } 23 | public Link getChildren() { 24 | return children; 25 | } 26 | public void setChildren(Link children) { 27 | this.children = children; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch06/DijkstraTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch06; 2 | 3 | public class DijkstraTest { 4 | 5 | public static void main(String[] args) { 6 | int[] vertexes = {1, 2, 3, 4, 5, 6}; 7 | MatrixGraph matrixGraph = new MatrixGraph(vertexes); 8 | matrixGraph.addEdge(1, 2, 16);matrixGraph.addEdge(2, 1, 16); 9 | matrixGraph.addEdge(1, 3, 1);matrixGraph.addEdge(3, 1, 1); 10 | matrixGraph.addEdge(1, 5, 12);matrixGraph.addEdge(5, 1, 12); 11 | matrixGraph.addEdge(1, 6, 15);matrixGraph.addEdge(6, 1, 15); 12 | matrixGraph.addEdge(2, 4, 2);matrixGraph.addEdge(4, 2, 2); 13 | matrixGraph.addEdge(2, 6, 8);matrixGraph.addEdge(6, 2, 8); 14 | matrixGraph.addEdge(3, 5, 5);matrixGraph.addEdge(5, 3, 5); 15 | matrixGraph.addEdge(4, 6, 3);matrixGraph.addEdge(6, 4, 3); 16 | matrixGraph.addEdge(5, 6, 8);matrixGraph.addEdge(6, 5, 8); 17 | matrixGraph.addEdge(4, 5, 9);matrixGraph.addEdge(5, 4, 9); 18 | matrixGraph.dijkstra(1); 19 | 20 | ListGraph listGraph = new ListGraph(vertexes); 21 | listGraph.addEdges(1, new int[]{2, 3, 5, 6}, new int[]{16, 1, 12, 15}); 22 | listGraph.addEdges(2, new int[]{1, 4, 6}, new int[]{16, 2, 8}); 23 | listGraph.addEdges(3, new int[]{1, 5}, new int[]{1, 5}); 24 | listGraph.addEdges(4, new int[]{2, 5, 6}, new int[]{2, 9, 3}); 25 | listGraph.addEdges(5, new int[]{1, 3, 4, 6}, new int[]{12, 5, 9, 8}); 26 | listGraph.addEdges(6, new int[]{1, 2, 4, 5}, new int[]{15, 8, 3, 8}); 27 | listGraph.dijkstra(1); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch06/ListGraph.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch06; 2 | 3 | import me.irfen.algorithm.ch01.HashTable; 4 | import me.irfen.algorithm.ch02.ArrayQueue; 5 | import me.irfen.algorithm.ch02.Stack; 6 | 7 | public class ListGraph { 8 | 9 | // 图的顶点数组 10 | private ListGraphNode[] nodes; 11 | private HashTable value2index = new HashTable(); 12 | 13 | /** 14 | * 初始化图的顶点 15 | * @param vertexes 16 | */ 17 | public ListGraph(int[] vertexes) { 18 | nodes = new ListGraphNode[vertexes.length]; 19 | for (int i = 0; i < vertexes.length; i++) { 20 | nodes[i] = new ListGraphNode(i, vertexes[i], null); 21 | value2index.put(vertexes[i], i); 22 | } 23 | } 24 | 25 | /** 26 | * 添加start到可到达的边 27 | * @param start 起始顶点 28 | * @param end 可到达的顶点的数组 29 | */ 30 | public void addEdges(int start, int[] end) { 31 | int index = value2index.get(start); 32 | if (index < 0) { 33 | throw new RuntimeException("未找到指定的起始顶点"); 34 | } 35 | ListGraphNode node = nodes[index]; 36 | for (int j = 0; j < end.length; j++) { 37 | int i = value2index.get(end[j]); 38 | if (i < 0) { 39 | throw new RuntimeException("未找到指定的到达顶点"); 40 | } 41 | node.next = new ListGraphNode(i, end[j], null); 42 | node = node.next; 43 | } 44 | } 45 | 46 | /** 47 | * 添加start到可到达的边 48 | * @param start 起始顶点 49 | * @param end 可到达的顶点的数组 50 | * @param weights 对应的权值数组 51 | */ 52 | public void addEdges(int start, int[] end, int[] weights) { 53 | int index = value2index.get(start); 54 | if (index < 0) { 55 | throw new RuntimeException("未找到指定的起始顶点"); 56 | } 57 | ListGraphNode node = nodes[index]; 58 | for (int j = 0; j < end.length; j++) { 59 | int i = value2index.get(end[j]); 60 | if (i < 0) { 61 | throw new RuntimeException("未找到指定的到达顶点"); 62 | } 63 | node.next = new ListGraphNode(i, end[j], weights[j], null); 64 | node = node.next; 65 | } 66 | } 67 | 68 | /** 69 | * 邻接表深度优先遍历 70 | */ 71 | public void depthFirstTravel() { 72 | System.out.println("邻接表的深度优先遍历:"); 73 | // 初始化栈 74 | Stack stack = new Stack(nodes.length); 75 | // 初始化各顶点访问状态 76 | int[] visited = new int[nodes.length]; 77 | // 从未访问顶点中任选一个顶点作为起始顶点 78 | int unvisited = getUnVisited(visited); 79 | while (unvisited >= 0) { 80 | visited[unvisited] = 1; 81 | stack.push(unvisited); 82 | System.out.print(nodes[unvisited].value + ","); 83 | while (!stack.isEmpty()) { 84 | // 获取栈顶元素不出栈 85 | int index = stack.peek(); 86 | // 找到未被访问的邻接顶点 87 | boolean found = false; 88 | ListGraphNode node = nodes[index]; 89 | while (node != null) { 90 | if (node.next != null && visited[node.next.index] == 0) { 91 | // 如果找到则访问并入栈 92 | visited[node.next.index] = 1; 93 | stack.push(node.next.index); 94 | System.out.print(node.next.value + ","); 95 | found = true; 96 | break; 97 | } 98 | node = node.next; 99 | } 100 | // 如果未找到则出栈元素 101 | if (!found) { 102 | stack.pop(); 103 | } 104 | } 105 | unvisited = getUnVisited(visited); 106 | } 107 | System.out.println(); 108 | } 109 | 110 | /** 111 | * 邻接表广度优先遍历 112 | */ 113 | public void breadthFirstTravel() { 114 | System.out.println("邻接表的广度优先遍历:"); 115 | // 初始化队列 116 | ArrayQueue queue = new ArrayQueue(nodes.length); 117 | // 初始化各顶点访问状态 118 | int[] visited = new int[nodes.length]; 119 | // 从未访问顶点中任选一个顶点作为起始顶点 120 | int unvisited = getUnVisited(visited); 121 | while (unvisited >= 0) { 122 | // 起始顶点入队 123 | queue.put(unvisited); 124 | while (!queue.isEmpty()) { 125 | // 出队顶点并访问 126 | int index = (Integer) queue.poll(); 127 | System.out.print(nodes[index].value + ","); 128 | // 标记被访问 129 | visited[index] = 1; 130 | // 遍历所有未被访问的邻接顶点,放入队列中 131 | ListGraphNode node = nodes[index].next; 132 | while (node != null) { 133 | if (visited[node.index] == 0) { 134 | queue.put(node.index); 135 | } 136 | node = node.next; 137 | } 138 | } 139 | unvisited = getUnVisited(visited); 140 | } 141 | System.out.println(); 142 | } 143 | 144 | /** 145 | * dijkstra算法实现到各点的最短路径 146 | * @param start 147 | */ 148 | public void dijkstra(int start) { 149 | int length = nodes.length; 150 | int x = value2index.get(start); // 根据哈希表获取对应的下标 151 | if (x == -1) { 152 | throw new RuntimeException("未找到起始顶点"); 153 | } 154 | int[] S = new int[length]; // 自动初始化为0,都属于未得到最短路径的顶点 155 | int[][] distance = new int[length][length]; // 存储v到u的最短距离 156 | int[] path = new int[length]; // 存储x到u最短路径时u的前一个顶点 157 | // 初始化distance和path数组 158 | for (int i = 0; i < length; i++) { 159 | // 先初始化path都为-1 160 | path[i] = -1; 161 | } 162 | for (int i = 0; i < length; i++) { 163 | ListGraphNode node = nodes[i]; 164 | node = node.next; 165 | while (node != null) { 166 | distance[i][node.index] = node.weight; 167 | if (x == i) { 168 | // 如果是x顶点的链表的话,初始化所有可达顶点的前一个顶点为x 169 | path[node.index] = x; 170 | } 171 | node = node.next; 172 | } 173 | } 174 | // 先把起始顶点加入到S 175 | S[x] = 1; 176 | for (int i = 0; i < length; i++) { 177 | // 首先需要寻找start顶点到各顶点最短的路径 178 | int min = Integer.MAX_VALUE; 179 | int v = 0; 180 | for (int j = 0; j < length; j++) { 181 | // S[j] == 1的话说明已经找到最短距离 182 | // 需要过滤掉不可达的情况 183 | if (S[j] != 1 && x != j && distance[x][j] != 0 && distance[x][j] < min) { 184 | min = distance[x][j]; 185 | v = j; 186 | } 187 | } 188 | // v是目前x到各顶点最短的 189 | S[v] = 1; 190 | // 修正最短距离distance及最短距离path 191 | for (int j = 0; j < length; j++) { 192 | // 1.只修正未找到最短路径的 193 | // 2.修正后新顶点需要可达 194 | // 3.如果使用新的最短路径比原有路径短,或者以前不可达,使用新的最短路径可达了 195 | // 符合上面三点可以修正路径 196 | if (S[j] != 1 && distance[v][j] != 0 197 | && (min + distance[v][j] < distance[x][j] || distance[x][j] == 0)) { 198 | // 说明加入了中间顶点之后找到了更短的路径 199 | distance[x][j] = min + distance[v][j]; 200 | path[j] = v; 201 | } 202 | } 203 | } 204 | // 打印最短路径值 205 | for (int i = 0; i < length; i++) { 206 | if (distance[x][i] != 0) { 207 | System.out.println(nodes[x].value + "-->" + nodes[i].value + ": " + distance[x][i]); 208 | // 由于path存储的特性,可以逆序输出路径,如果有兴趣可以用栈实现正序输出 209 | System.out.print("逆序最短路径输出:"); 210 | int index = i; 211 | while (index != -1) { 212 | System.out.print(nodes[index].value); 213 | index = path[index]; 214 | } 215 | System.out.println(); 216 | } 217 | } 218 | } 219 | 220 | /** 221 | * 打印出邻接表数据 222 | */ 223 | public void printListGraph() { 224 | for (int i = 0; i < nodes.length; i++) { 225 | ListGraphNode node = nodes[i]; 226 | do { 227 | System.out.print(node.value); 228 | node = node.next; 229 | } while (node != null); 230 | System.out.println(); 231 | } 232 | } 233 | 234 | /** 235 | * 从访问标记数组中获取第一个发现的未被访问的顶点下标 236 | * @param visited 237 | * @return 都被访问了就返回-1 238 | */ 239 | private int getUnVisited(int[] visited) { 240 | int index = -1; 241 | for (int i = 0; i < visited.length; i++) { 242 | if (visited[i] == 0) { 243 | index = i; 244 | break; 245 | } 246 | } 247 | return index; 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch06/ListGraphNode.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch06; 2 | 3 | public class ListGraphNode { 4 | 5 | int index; 6 | /// 值 7 | int value; 8 | // 权值 9 | int weight; 10 | // 指向下一个节点的指针(引用) 11 | ListGraphNode next; 12 | 13 | public ListGraphNode(int value, ListGraphNode next) { 14 | this.value = value; 15 | this.next = next; 16 | } 17 | 18 | public ListGraphNode(int index, int value, ListGraphNode next) { 19 | this.index = index; 20 | this.value = value; 21 | this.next = next; 22 | } 23 | 24 | public ListGraphNode(int index, int value, int weight, ListGraphNode next) { 25 | this.index = index; 26 | this.value = value; 27 | this.weight = weight; 28 | this.next = next; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch06/ListGraphTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch06; 2 | 3 | public class ListGraphTest { 4 | 5 | public static void main(String[] args) { 6 | int[] vertexes = {0, 1, 2, 3}; 7 | ListGraph graph = new ListGraph(vertexes); 8 | graph.addEdges(0, new int[]{1, 2, 3}); 9 | graph.addEdges(1, new int[]{2}); 10 | graph.addEdges(3, new int[]{2}); 11 | graph.printListGraph(); 12 | 13 | int[] vertexes2 = {0, 1, 2, 3, 4, 5, 6}; 14 | ListGraph graph2 = new ListGraph(vertexes2); 15 | graph2.addEdges(0, new int[]{1, 2}); 16 | graph2.addEdges(1, new int[]{3, 4}); 17 | graph2.addEdges(2, new int[]{5, 6}); 18 | graph2.depthFirstTravel(); 19 | graph2.breadthFirstTravel(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch06/MatrixGraph.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch06; 2 | 3 | import me.irfen.algorithm.ch02.ArrayQueue; 4 | import me.irfen.algorithm.ch02.Stack; 5 | 6 | public class MatrixGraph { 7 | 8 | // 通过下标映射元素值 9 | private int[] mapping; 10 | // 图的二维数组 11 | private int[][] matrix; 12 | 13 | /** 14 | * 初始化图的顶点 15 | * @param vertexes 顶点数组 16 | */ 17 | public MatrixGraph(int[] vertexes) { 18 | int length = vertexes.length; 19 | mapping = new int[length]; 20 | matrix = new int[length][length]; 21 | for (int i = 0; i < length; i++) { 22 | mapping[i] = vertexes[i]; 23 | } 24 | } 25 | 26 | /** 27 | * 添加边 28 | * @param start 29 | * @param end 30 | */ 31 | public void addEdge(int start, int end) { 32 | int x = -1; 33 | int y = -1; 34 | // 寻找坐标 35 | for (int i = 0; i < mapping.length; i++) { 36 | if (x != -1 && y != -1) { 37 | break; 38 | } 39 | if (start == mapping[i]) { 40 | x = i; 41 | } 42 | if (end == mapping[i]) { 43 | y = i; 44 | } 45 | } 46 | // 判断顶点是否存在 47 | if (x == -1 || y == -1 48 | || x > mapping.length - 1 || y > mapping.length - 1) { 49 | throw new IndexOutOfBoundsException("边的顶点不存在"); 50 | } 51 | // 增加边 52 | matrix[x][y] = 1; 53 | } 54 | 55 | /** 56 | * 添加具有权值的边 57 | * @param start 58 | * @param end 59 | * @param value 60 | */ 61 | public void addEdge(int start, int end, int value) { 62 | int x = -1; 63 | int y = -1; 64 | // 寻找坐标 65 | for (int i = 0; i < mapping.length; i++) { 66 | if (x != -1 && y != -1) { 67 | break; 68 | } 69 | if (start == mapping[i]) { 70 | x = i; 71 | } 72 | if (end == mapping[i]) { 73 | y = i; 74 | } 75 | } 76 | // 判断顶点是否存在 77 | if (x == -1 || y == -1 78 | || x > mapping.length - 1 || y > mapping.length - 1) { 79 | throw new IndexOutOfBoundsException("边的顶点不存在"); 80 | } 81 | // 增加边 82 | matrix[x][y] = value; 83 | } 84 | 85 | /** 86 | * 邻接矩阵深度优先遍历 87 | */ 88 | public void depthFirstTravel() { 89 | System.out.println("邻接矩阵的深度优先遍历:"); 90 | // 初始化栈 91 | Stack stack = new Stack(mapping.length); 92 | // 初始化各顶点访问状态 93 | int[] visited = new int[mapping.length]; 94 | // 从未访问顶点中任选一个顶点作为起始顶点 95 | int unvisited = getUnVisited(visited); 96 | while (unvisited >= 0) { 97 | // 访问起始顶点并入栈 98 | visited[unvisited] = 1; 99 | stack.push(unvisited); 100 | System.out.print(mapping[unvisited] + ","); 101 | while (!stack.isEmpty()) { 102 | // 获取栈顶元素不出栈 103 | int index = stack.peek(); 104 | // 遍历找到未被访问的邻接顶点 105 | boolean found = false; 106 | for (int i = 0; i < mapping.length; i++) { 107 | // 不能是自己、未被访问、可到达 108 | if (index != i && visited[i] == 0 && matrix[index][i] > 0) { 109 | // 如果找到则访问并入栈 110 | visited[i] = 1; 111 | stack.push(i); 112 | System.out.print(mapping[i] + ","); 113 | found = true; 114 | break; 115 | } 116 | } 117 | // 如果未找到则出栈元素 118 | if (!found) { 119 | stack.pop(); 120 | } 121 | } 122 | unvisited = getUnVisited(visited); 123 | } 124 | System.out.println(); 125 | } 126 | 127 | /** 128 | * 邻接矩阵广度优先遍历 129 | */ 130 | public void breadthFirstTravel() { 131 | System.out.println("邻接矩阵的广度优先遍历:"); 132 | // 初始化队列 133 | ArrayQueue queue = new ArrayQueue(mapping.length); 134 | // 初始化各顶点访问状态 135 | int[] visited = new int[mapping.length]; 136 | // 从未访问顶点中任选一个顶点作为起始顶点 137 | int unvisited = getUnVisited(visited); 138 | while (unvisited >= 0) { 139 | // 起始顶点入队 140 | queue.put(unvisited); 141 | while (!queue.isEmpty()) { 142 | // 出队顶点并访问 143 | int index = (Integer) queue.poll(); 144 | if (visited[index] == 1) { 145 | continue; 146 | } 147 | System.out.print(mapping[index] + ","); 148 | // 标记被访问 149 | visited[index] = 1; 150 | // 遍历所有未被访问的邻接顶点,放入队列中 151 | for (int i = 0; i < mapping.length; i++) { 152 | // 不能是自己、未被访问、可到达 153 | if (index != i && visited[i] == 0 && matrix[index][i] > 0) { 154 | queue.put(i); 155 | } 156 | } 157 | } 158 | unvisited = getUnVisited(visited); 159 | } 160 | System.out.println(); 161 | } 162 | 163 | /** 164 | * dijkstra算法实现到各点的最短路径 165 | * @param start 166 | */ 167 | public void dijkstra(int start) { 168 | int length = mapping.length; 169 | int x = -1; 170 | for (int i = 0; i < length; i++) { 171 | if (mapping[i] == start) { 172 | x = i; 173 | break; 174 | } 175 | } 176 | if (x == -1) { 177 | throw new RuntimeException("未找到起始顶点"); 178 | } 179 | 180 | int[] S = new int[length]; // 自动初始化为0,都属于未得到最短路径的顶点 181 | int[][] distance = matrix; // 存储v到u的最短距离 182 | int[] path = new int[length]; // 存储x到u最短路径时u的前一个顶点 183 | // 初始化path数组 184 | for (int i = 0; i < length; i++) { 185 | // 如果可达就赋值 186 | if (matrix[x][i] > 0) { 187 | path[i] = x; 188 | } else { 189 | // 不可达,赋值前一个顶点下标为-1 190 | path[i] = -1; 191 | } 192 | } 193 | // 先把起始顶点加入到S 194 | S[x] = 1; 195 | for (int i = 0; i < length; i++) { 196 | // 首先需要寻找start顶点到各顶点最短的路径 197 | int min = Integer.MAX_VALUE; 198 | int v = 0; 199 | for (int j = 0; j < length; j++) { 200 | // S[j] == 1的话说明已经找到最短距离 201 | // 需要过滤掉不可达的情况 202 | if (S[j] != 1 && x != j && distance[x][j] != 0 && distance[x][j] < min) { 203 | min = distance[x][j]; 204 | v = j; 205 | } 206 | } 207 | // v是目前x到各顶点最短的 208 | S[v] = 1; 209 | // 修正最短距离distance及最短距离path 210 | for (int j = 0; j < length; j++) { 211 | // 1.只修正未找到最短路径的 212 | // 2.修正后新顶点需要可达 213 | // 3.如果使用新的最短路径比原有路径短,或者以前不可达,使用新的最短路径可达了 214 | // 符合上面三点可以修正路径 215 | if (S[j] != 1 && distance[v][j] != 0 216 | && (min + distance[v][j] < distance[x][j] || distance[x][j] == 0)) { 217 | // 说明加入了中间顶点之后找到了更短的路径 218 | distance[x][j] = min + distance[v][j]; 219 | path[j] = v; 220 | } 221 | } 222 | } 223 | // 打印最短路径值 224 | for (int i = 0; i < length; i++) { 225 | if (distance[x][i] != 0) { 226 | System.out.println(mapping[x] + "-->" + mapping[i] + ": " + distance[x][i]); 227 | // 由于path存储的特性,可以逆序输出路径,如果有兴趣可以用栈实现正序输出 228 | System.out.print("逆序最短路径输出:"); 229 | int index = i; 230 | while (index != -1) { 231 | System.out.print(mapping[index]); 232 | index = path[index]; 233 | } 234 | System.out.println(); 235 | } 236 | } 237 | } 238 | 239 | /** 240 | * 输出矩阵 241 | */ 242 | public void printMatrix() { 243 | for (int i = 0; i < matrix.length; i++) { 244 | for (int j = 0; j < matrix[i].length; j++) { 245 | System.out.print(matrix[i][j]); 246 | } 247 | System.out.println(); 248 | } 249 | } 250 | 251 | /** 252 | * 从访问标记数组中获取第一个发现的未被访问的顶点下标 253 | * @param visited 254 | * @return 都被访问了就返回-1 255 | */ 256 | private int getUnVisited(int[] visited) { 257 | int index = -1; 258 | for (int i = 0; i < visited.length; i++) { 259 | if (visited[i] == 0) { 260 | index = i; 261 | break; 262 | } 263 | } 264 | return index; 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch06/MatrixGraphTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch06; 2 | 3 | public class MatrixGraphTest { 4 | 5 | public static void main(String[] args) { 6 | int[] vertexes = {0, 1, 2, 3}; 7 | // 初始化图 8 | MatrixGraph graph = new MatrixGraph(vertexes); 9 | graph.addEdge(0, 1); 10 | graph.addEdge(0, 2); 11 | graph.addEdge(0, 3); 12 | graph.addEdge(1, 2); 13 | graph.addEdge(3, 2); 14 | graph.printMatrix(); 15 | 16 | int[] vertexes2 = {0, 1, 2, 3, 4, 5, 6}; 17 | MatrixGraph graph2 = new MatrixGraph(vertexes2); 18 | graph2.addEdge(0, 1); 19 | graph2.addEdge(0, 2); 20 | graph2.addEdge(1, 3); 21 | graph2.addEdge(1, 4); 22 | graph2.addEdge(2, 5); 23 | graph2.addEdge(2, 6); 24 | graph2.printMatrix(); 25 | graph2.depthFirstTravel(); 26 | graph2.breadthFirstTravel(); 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch07/FullPermutation.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch07; 2 | 3 | public class FullPermutation { 4 | 5 | /** 6 | * 字符串全排列的递归实现 7 | * @param str 8 | */ 9 | public static void recursivePermutation(String str) { 10 | char[] array = str.toCharArray(); 11 | recursivePermutation(array, 0, array.length -1); 12 | } 13 | 14 | /** 15 | * 字符串全排列的递归实现 16 | * 17 | * @param array 字符数组 18 | * @param start 起始下标 19 | * @param end 结束下标 20 | */ 21 | private static void recursivePermutation(char[] array, int start, int end) { 22 | // 当递归到最后一位的时候start与end相等,这时候输出排列 23 | if (start == end) { 24 | for (int i = 0; i <= end; i++) { 25 | System.out.print(array[i]); 26 | } 27 | System.out.println(); 28 | } else { 29 | // 从开始一直遍历并递归执行后面部分的全排列 30 | for (int j = start; j <= end; j++) { 31 | // 与当前递归的部分的首位进行交换 32 | swap(array, j, start); 33 | // 递归全排列后面的部分 34 | recursivePermutation(array, start + 1, end); 35 | // 交换回去保持原样 36 | swap(array, j, start); 37 | } 38 | } 39 | } 40 | 41 | /** 42 | * ASCII码排序全排列 43 | * @param str 44 | */ 45 | public static void asciiPermutation(String str) { 46 | // 获取字符串每个字符的ASCII 47 | char[] array = str.toCharArray(); 48 | // 需要先排序 49 | shellSort(array); 50 | int length = array.length; 51 | int i = 0; 52 | while (true) { 53 | System.out.println(array); 54 | // 找到数组中第一个打乱次序的坏人的位置 55 | for (i = length - 2; (i >= 0) && (array[i] >= array[i + 1]); --i) { 56 | ; 57 | } 58 | // 当i<0时说明已经遍历到第一个元素的前面了,结束 59 | if (i < 0) { 60 | return; 61 | } 62 | int j; 63 | // 找到排列中第i位右边最后一个比其大的数的位置j 64 | for (j = length - 1; (j > i) && (array[j] <= array[i]); --j) { 65 | ; 66 | } 67 | // 交换i、j的值 68 | swap(array, i, j); 69 | // 把i位置后面的部分内容反转 70 | reverse(array, i + 1, length - 1); 71 | } 72 | } 73 | 74 | /** 75 | * 字符数组指定位置的互换 76 | * @param array 77 | * @param left 78 | * @param right 79 | */ 80 | private static void swap(char[] array, int left, int right) { 81 | char temp = array[left]; 82 | array[left] = array[right]; 83 | array[right] = temp; 84 | } 85 | 86 | /** 87 | * 字符数组指定区间的反转 88 | * @param array 89 | * @param start 90 | * @param end 91 | */ 92 | private static void reverse(char[] array, int start, int end) { 93 | int mid = (end - start) / 2 + start; 94 | for (int i = 0; i <= mid - start; i++) { 95 | swap(array, start + i, end - i); 96 | } 97 | } 98 | 99 | /** 100 | * 根据字符ASCII码进行希尔排序 101 | * @param array 102 | */ 103 | private static void shellSort(char[] array) { 104 | char temp; 105 | for (int k = array.length / 2; k > 0; k /= 2) { 106 | for (int i = k; i < array.length; i++) { 107 | for (int j = i; j >= k; j -= k) { 108 | if (array[j - k] > array[j]) { 109 | temp = array[j - k]; 110 | array[j - k] = array[j]; 111 | array[j] = temp; 112 | } 113 | } 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch07/FullPermutationTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch07; 2 | 3 | public class FullPermutationTest { 4 | 5 | public static void main(String[] args) { 6 | FullPermutation.recursivePermutation("bcad"); 7 | 8 | FullPermutation.asciiPermutation("bcda"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch07/Reverse.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch07; 2 | 3 | public class Reverse { 4 | 5 | public static String reverse(String str, int start, int end) { 6 | // 先转换为字符数组 7 | char[] array = str.toCharArray(); 8 | // 初始化已完成反转第一个字符位置(默认为待反转外面) 9 | int finish = end + 1; 10 | // 如果已完成的首字符减到start,则说明反转完成 11 | while (finish > start) { 12 | char temp = array[start]; 13 | for (int j = start + 1; j < finish; j++) { 14 | array[j - 1] = array[j]; 15 | } 16 | array[finish - 1] = temp; 17 | finish --; 18 | } 19 | return String.valueOf(array); 20 | } 21 | 22 | /** 23 | * 对换位置反转字符 24 | * @param str 25 | * @param start 26 | * @param end 27 | * @return 28 | */ 29 | public static String reverse2(String str, int start, int end) { 30 | char[] array = str.toCharArray(); 31 | int mid = (end - start) / 2 + start; 32 | for (int i = 0; i <= mid - start; i++) { 33 | swap(array, start + i, end - i); 34 | } 35 | return String.valueOf(array); 36 | } 37 | 38 | /** 39 | * 旋转字符串 40 | * @param str 41 | * @param index 42 | * @return 43 | */ 44 | public static String rotate(String str, int index) { 45 | str = reverse2(str, 0, index); 46 | str = reverse2(str, index + 1, str.length() - 1); 47 | str = reverse2(str, 0, str.length() - 1); 48 | return str; 49 | } 50 | 51 | /** 52 | * 字符数组指定位置的互换 53 | * @param array 54 | * @param left 55 | * @param right 56 | */ 57 | private static void swap(char[] array, int left, int right) { 58 | char temp = array[left]; 59 | array[left] = array[right]; 60 | array[right] = temp; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch07/ReverseTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch07; 2 | 3 | public class ReverseTest { 4 | 5 | public static void main(String[] args) { 6 | System.out.println(Reverse.reverse("abcdefg", 0, 6)); 7 | System.out.println(Reverse.reverse("abcdefg", 2, 4)); 8 | System.out.println(Reverse.reverse2("abcdefg", 0, 6)); 9 | System.out.println(Reverse.reverse2("abcdefg", 2, 4)); 10 | 11 | System.out.println(Reverse.rotate("abcdefg", 3)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch07/StringContainsUtil.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch07; 2 | 3 | import me.irfen.algorithm.ch01.HashTable; 4 | 5 | public class StringContainsUtil { 6 | 7 | /** 8 | * 暴力比对法 9 | * @param str1 10 | * @param str2 11 | * @return 12 | */ 13 | public static boolean contains(String str1, String str2) { 14 | for (int i = 0; i < str2.length(); i++) { 15 | char b = str2.charAt(i); 16 | int count = 0; 17 | for (int j = 0; j < str1.length(); j++) { 18 | char a = str1.charAt(j); 19 | // 如果字符不等,则累加不等的个数 20 | if (a != b) { 21 | count++; 22 | } 23 | } 24 | // 如果最终不等的个数刚好等于str1字符串长度, 25 | // 说明都不等,也就是不包含 26 | if (count == str1.length()) { 27 | return false; 28 | } 29 | } 30 | return true; 31 | } 32 | 33 | /** 34 | * 利用快排和双指针比对 35 | * @param str1 36 | * @param str2 37 | * @return 38 | */ 39 | public static boolean contains2(String str1, String str2) { 40 | char[] c1 = str1.toCharArray(); 41 | char[] c2 = str2.toCharArray(); 42 | quickSort(c1, 0, c1.length - 1); 43 | quickSort(c2, 0, c2.length - 1); 44 | for (int p1 = 0, p2 = 0; p2 < c2.length; p2 ++) { 45 | while ((p1 < c1.length) && (c1[p1] < c2[p2])) { 46 | p1 ++; 47 | } 48 | // 如果超出长度或者找到大于的值都说明不包含 49 | if ((p1 >= c1.length) || (c1[p1] > c2[p2])) { 50 | return false; 51 | } 52 | } 53 | return true; 54 | } 55 | 56 | /** 57 | * 素数方式实现字符串包含 58 | * @param str1 59 | * @param str2 60 | * @return 61 | */ 62 | public static boolean contains3(String str1, String str2) { 63 | // 素数数组 64 | int prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,61, 67, 71, 73, 79, 83, 89, 97, 101}; 65 | int all = 1; // 初始化为1 66 | for (int i = 0; i < str1.length(); i ++) { 67 | int x = prime[str1.charAt(i) - 'A']; 68 | // 如果不包含,则累计 69 | if (all % x != 0) { 70 | all *= x; 71 | } 72 | } 73 | for (int i = 0; i < str2.length(); i ++) { 74 | int x = prime[str2.charAt(i) - 'A']; 75 | // 依次判断是否包含str2中的字符 76 | if (all % x != 0) { 77 | return false; 78 | } 79 | } 80 | return true; 81 | } 82 | 83 | /** 84 | * 散列表方式实现是否包含 85 | * @param str1 86 | * @param str2 87 | * @return 88 | */ 89 | public static boolean contains4(String str1, String str2) { 90 | HashTable hashTable = new HashTable(); 91 | for (int i = 0; i < str1.length(); i++) { 92 | // 依次把str1中的字符放入散列表 93 | // 散列表的值没用,随便放个1 94 | hashTable.put(str1.charAt(i), 1); 95 | } 96 | for (int i = 0; i < str2.length(); i++) { 97 | int value = hashTable.get(str2.charAt(i)); 98 | if (value != 1) { 99 | return false; 100 | } 101 | } 102 | return true; 103 | } 104 | 105 | /** 106 | * 使用位运算实现是否包含 107 | * @param str1 108 | * @param str2 109 | * @return 110 | */ 111 | public static boolean contains5(String str1, String str2) { 112 | int result = 0; 113 | for (int i = 0; i < str1.length(); i ++) { 114 | result |= (1 << (str1.charAt(i) - 'A')); 115 | } 116 | for (int i = 0; i < str2.length(); i ++) { 117 | if ((result & (1 << (str2.charAt(i) - 'A'))) == 0) { 118 | return false; 119 | } 120 | } 121 | return true; 122 | } 123 | 124 | /** 125 | * 递归排序 126 | * @param src 127 | * @param begin 128 | * @param end 129 | */ 130 | private static void quickSort(char[] src, int begin, int end) { 131 | if (begin < end) { 132 | char key = src[begin]; 133 | int i = begin; 134 | int j = end; 135 | 136 | while (i < j) { 137 | while (i < j && src[j] > key) { 138 | j--; 139 | } 140 | if (i < j) { 141 | src[i] = src[j]; 142 | i++; 143 | } 144 | while (i < j && src[i] < key) { 145 | i++; 146 | } 147 | if (i < j) { 148 | src[j] = src[i]; 149 | j--; 150 | } 151 | } 152 | 153 | src[i] = key; 154 | 155 | quickSort(src, begin, i - 1); 156 | quickSort(src, i + 1, end); 157 | } 158 | 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch07/StringContainsUtilTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch07; 2 | 3 | public class StringContainsUtilTest { 4 | 5 | public static void main(String[] args) { 6 | String str1 = "ABCDEFG", str2 = "BDBG", str3 = "BDBQ"; 7 | System.out.println(StringContainsUtil.contains(str1, str2)); 8 | System.out.println(StringContainsUtil.contains(str1, str3)); 9 | 10 | System.out.println(StringContainsUtil.contains2(str1, str2)); 11 | System.out.println(StringContainsUtil.contains2(str1, str3)); 12 | 13 | System.out.println(StringContainsUtil.contains3(str1, str2)); 14 | System.out.println(StringContainsUtil.contains3(str1, str3)); 15 | 16 | System.out.println(StringContainsUtil.contains4(str1, str2)); 17 | System.out.println(StringContainsUtil.contains4(str1, str3)); 18 | 19 | System.out.println(StringContainsUtil.contains5(str1, str2)); 20 | System.out.println(StringContainsUtil.contains5(str1, str3)); 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch07/StringUtils.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch07; 2 | 3 | public class StringUtils { 4 | 5 | /** 6 | * 判断回文字符串 7 | * @param str 8 | * @return 9 | */ 10 | public static boolean isPalindrome(String str) { 11 | if (str == null || str.length() == 0) { 12 | throw new RuntimeException("字符串为空"); 13 | } 14 | int middle = (str.length() - 1) / 2; 15 | for (int i = 0; i <= middle; i++) { 16 | if (str.charAt(i) != str.charAt(str.length() - 1 - i)) { 17 | return false; 18 | } 19 | } 20 | return true; 21 | } 22 | 23 | /** 24 | * 计算回文字符最大子串长度 25 | * @param str 26 | * @return 27 | */ 28 | public static int longestPalindrome(String str) { 29 | if (str == null || str.length() < 1) { 30 | return 0; 31 | } 32 | int max = 0, current = 0, length = str.length(); 33 | 34 | // 循环每个字符为回文的中点 35 | for (int i = 0; i < length; ++i) { 36 | // 考虑回文子串为奇数长度的情况 37 | for (int j = 0; i - j >= 0 && i + j < length; j++) { 38 | // 如果不想等,则不继续累加回文子串长度 39 | if (str.charAt(i - j) != str.charAt(i + j)) { 40 | break; 41 | } 42 | current = j * 2 + 1; 43 | } 44 | // 如果得到的长度比max大,则更新max 45 | if (current > max) { 46 | max = current; 47 | } 48 | // 重置current(其实这里不重置也不影响后面的结果) 49 | current = 0; 50 | // 考虑回文子串为偶数长度的情况 51 | for (int j = 0; (i - j >= 0) && (i + j + 1 < length); j++){ 52 | if (str.charAt(i - j) != str.charAt(i + j + 1)) { 53 | break; 54 | } 55 | current = j * 2 + 2; 56 | } 57 | if (current > max) { 58 | max = current; 59 | } 60 | } 61 | return max; 62 | } 63 | 64 | public static int toInt(String str) { 65 | if (str == null || str.length() == 0) { 66 | throw new RuntimeException("字符串为空"); 67 | } 68 | // 转换结果 69 | int result = 0; 70 | // 转换的字符 71 | int current = 0; 72 | // 整数的正负 73 | char sign = '+'; 74 | // 如果首位是符号的话,赋值符号正负 75 | if (str.charAt(0) == '-' || str.charAt(0) == '+') { 76 | sign = str.charAt(0); 77 | // 如果有符号,则转换内容截取掉首位字符 78 | str = str.substring(1); 79 | } 80 | // 是否需要判断溢出 81 | boolean judgeOverflow = true; 82 | if (str.length() > 10) { 83 | throw new RuntimeException("整型溢出了"); 84 | } else if (str.length() < 10) { 85 | judgeOverflow = false; 86 | } 87 | for (int i = 0; i < str.length(); i++) { 88 | current = str.charAt(i) - '0'; 89 | if (current > 9 || current < 0) { 90 | throw new RuntimeException("包含非整型数字字符"); 91 | } 92 | if (judgeOverflow) { 93 | if (sign == '+' 94 | && (result == 0 || result == Integer.MAX_VALUE / (int) Math.pow(10, 9 - i + 1)) 95 | && current > Integer.MAX_VALUE / (int) Math.pow(10, 9 - i) % 10) { 96 | System.err.println(current); 97 | throw new RuntimeException("整型溢出了"); 98 | } 99 | if (sign == '-' 100 | && (result == 0 || result == -(Integer.MIN_VALUE / (int) Math.pow(10, 9 - i + 1))) 101 | && current > -(Integer.MIN_VALUE / (int) Math.pow(10, 9 - i) % 10)) { 102 | System.err.println(current); 103 | throw new RuntimeException("整型溢出了"); 104 | } 105 | } 106 | result = result * 10 + current; 107 | } 108 | if (sign == '-') { 109 | result = - result; 110 | } 111 | return result; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch07/StringUtilsTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch07; 2 | 3 | public class StringUtilsTest { 4 | 5 | public static void main(String[] args) { 6 | System.out.println(StringUtils.isPalindrome("abcba")); 7 | System.out.println(StringUtils.isPalindrome("abccba")); 8 | System.out.println(StringUtils.isPalindrome("abdbd")); 9 | 10 | System.out.println(StringUtils.longestPalindrome("abcdefgfedcgcda")); 11 | 12 | System.out.println(StringUtils.toInt("-12345")); 13 | System.out.println(StringUtils.toInt("12345")); 14 | 15 | System.out.println(StringUtils.toInt("-1234567890")); 16 | System.out.println(StringUtils.toInt("-2147483648")); 17 | 18 | System.out.println(StringUtils.toInt("1234567890")); 19 | System.out.println(StringUtils.toInt("2147483647")); 20 | 21 | System.out.println(StringUtils.toInt("2157483647")); 22 | System.out.println(StringUtils.toInt("-2147484648")); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/ArrayDot.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class ArrayDot { 4 | 5 | /** 6 | * 直接遍历法 7 | * @param array 8 | */ 9 | public static void findDot1(int[] array) { 10 | for (int i = 1; i < array.length; i++) { 11 | if (array[i] < array[i - 1]) { 12 | System.out.println("拐点元素为" + array[i] + "下标为" + i); 13 | return; 14 | } 15 | } 16 | } 17 | 18 | /** 19 | * 二分查找 20 | * @param array 21 | */ 22 | public static void findDot2(int[] array) { 23 | int low = 0; 24 | int high = array.length - 1; 25 | while (low < high) { 26 | if (high - low == 1) { 27 | // 如果只剩两个元素的话 28 | if (array[low] < array[0]) { 29 | System.out.println("拐点元素为" + array[low] + "下标为" + low); 30 | return; 31 | } else { 32 | System.out.println("拐点元素为" + array[high] + "下标为" + high); 33 | return; 34 | } 35 | } 36 | int middle = (low + high) / 2; 37 | if (array[middle] >= array[low]) { 38 | // 说明左边是非递减的,拐点在右边 39 | low = middle; 40 | } else { 41 | high = middle; 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/ArrayDotTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class ArrayDotTest { 4 | 5 | public static void main(String[] args) { 6 | int[] array = {4, 5, 6, 7, 1, 2, 3}; 7 | int[] array2 = {1, 1, 1, 0, 0, 0, 1}; 8 | ArrayDot.findDot1(array); 9 | ArrayDot.findDot1(array2); 10 | ArrayDot.findDot2(array); 11 | ArrayDot.findDot2(array2); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/ArraySort.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class ArraySort { 4 | 5 | /** 6 | * 两次遍历填充法 7 | * @param array 8 | */ 9 | public static void sort1(int[] array) { 10 | int[] result = new int[array.length]; 11 | int index = 0; 12 | for (int i = 0; i < array.length; i++) { 13 | if (array[i] < 0) { 14 | result[index++] = array[i]; 15 | } 16 | } 17 | for (int i = 0; i < array.length; i++) { 18 | if (array[i] >= 0) { 19 | result[index++] = array[i]; 20 | } 21 | } 22 | System.out.print("两次遍历填充法排序后结果:"); 23 | for (int i = 0; i < result.length; i++) { 24 | System.out.print(result[i]); 25 | if (i != result.length - 1) { 26 | System.out.print(","); 27 | } 28 | } 29 | System.out.println(); 30 | } 31 | 32 | /** 33 | * 借鉴简单插入排序思想 34 | * @param array 35 | */ 36 | public static void sort2(int[] array) { 37 | int index = 0; // 分界index 38 | for (int i = 0; i < array.length; i++) { 39 | if (array[i] < 0) { 40 | // 如果是负数,就依次前移到分解处 41 | for (int j = i; j > index; j--) { 42 | int temp = array[j - 1]; 43 | array[j - 1] = array[j]; 44 | array[j] = temp; 45 | } 46 | // 分界指针后移 47 | index ++; 48 | } 49 | } 50 | System.out.print("借鉴简单插入排序的排序后结果:"); 51 | for (int i = 0; i < array.length; i++) { 52 | System.out.print(array[i]); 53 | if (i != array.length - 1) { 54 | System.out.print(","); 55 | } 56 | } 57 | System.out.println(); 58 | } 59 | 60 | /** 61 | * 借鉴快速排序思想 62 | * @param array 63 | */ 64 | public static void sort3(int[] array) { 65 | int i = 0; 66 | int j = array.length - 1; 67 | while (i != j) { 68 | while (i < j && array[i] < 0) { 69 | i ++; 70 | } 71 | while (i < j && array[j] >= 0) { 72 | j --; 73 | } 74 | if (i < j) { 75 | int temp = array[i]; 76 | array[i] = array[j]; 77 | array[j] = temp; 78 | } 79 | } 80 | System.out.print("借鉴快速排序的排序后结果:"); 81 | for (int k = 0; k < array.length; k++) { 82 | System.out.print(array[k]); 83 | if (k != array.length - 1) { 84 | System.out.print(","); 85 | } 86 | } 87 | System.out.println(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/ArraySortTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class ArraySortTest { 4 | 5 | public static void main(String[] args) { 6 | int[] array1 = {1, -2, -4, 5, 9, -3, -8, 6}; 7 | int[] array2 = {1, -2, -4, 5, 9, -3, -8, 6}; 8 | int[] array3 = {1, -2, -4, 5, 9, -3, -8, 6}; 9 | ArraySort.sort1(array1); 10 | ArraySort.sort2(array2); 11 | ArraySort.sort3(array3); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/AssignArray.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class AssignArray { 4 | 5 | /** 6 | * 数组赋值 7 | * @param a 8 | */ 9 | public static void assign(int[] a) { 10 | int[] b = new int[a.length]; 11 | b[0] = 1; // 用作临时变量 12 | for (int i = 1; i < a.length; i++) { 13 | b[0] *= a[i - 1]; // 从前往后乘 得到Ba; 14 | b[i] = b[0]; // 此时b[i]为对应的Ba值 15 | } 16 | b[0] = 1; // 重置 17 | for (int i = a.length - 2; i > 0; i--) { 18 | b[0] *= a[i + 1]; // 从后往前 乘得到Bb; 19 | b[i] *= b[0]; // 把之前得到的Ba乘以这次得到的Bb 20 | } 21 | // 此时的b[0]就是a[2]*...a[n - 1]了 22 | b[0] *= a[1]; // 不要忘记算出b[0],乘以a[1]就好 23 | 24 | System.out.print("赋值后结果:"); 25 | for (int i = 0; i < b.length; i++) { 26 | System.out.print(b[i]); 27 | if (i != b.length - 1) { 28 | System.out.print(","); 29 | } 30 | } 31 | System.out.println(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/AssignArrayTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class AssignArrayTest { 4 | 5 | public static void main(String[] args) { 6 | int[] a = {1, 2, 3, 4, 5, 6}; 7 | AssignArray.assign(a); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/DutchFlag.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class DutchFlag { 4 | 5 | /** 6 | * 荷兰国旗问题 7 | * @param array 8 | */ 9 | public static void sort(int[] array) { 10 | int begin = 0; 11 | int end = array.length - 1; 12 | int current = 0; 13 | while (current <= end) { 14 | if (array[current] == 0) { 15 | swap(array, current, begin); 16 | begin ++; 17 | current ++; 18 | } else if (array[current] == 1) { 19 | current ++; 20 | } else if (array[current] == 2) { 21 | swap(array, current, end); 22 | end --; 23 | } 24 | } 25 | System.out.print("排序后结果:"); 26 | for (int i = 0; i < array.length; i++) { 27 | System.out.print(array[i]); 28 | if (i != array.length - 1) { 29 | System.out.print(","); 30 | } 31 | } 32 | System.out.println(); 33 | } 34 | 35 | private static void swap(int[] array, int x, int y) { 36 | int temp = array[x]; 37 | array[x] = array[y]; 38 | array[y] = temp; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/DutchFlagTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class DutchFlagTest { 4 | 5 | public static void main(String[] args) { 6 | int[] array1 = {1, 1, 0, 0, 2, 2, 1, 0, 1, 2, 1, 0, 2}; 7 | int[] array2 = {0, 1, 0, 0, 2, 2, 1, 0, 1, 2, 1, 0, 1}; 8 | DutchFlag.sort(array1); 9 | DutchFlag.sort(array2); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/MaxSumSubArray.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class MaxSumSubArray { 4 | 5 | /** 6 | * 暴力穷举法 7 | * @param array 8 | */ 9 | public static void find1(int[] array) { 10 | int maxSum = array[0]; 11 | int currentSum = 0; 12 | int start = 0; 13 | int end = 0; 14 | for (int i = 0; i < array.length; i++) { 15 | for (int j = i; j < array.length; j++) { 16 | for (int k = i; k <= j; k++) { 17 | currentSum += array[k]; 18 | } 19 | // 如果本次的和大于之前累加的最大和,就重新赋值 20 | if (currentSum > maxSum) { 21 | maxSum = currentSum; 22 | start = i; 23 | end = j; 24 | } 25 | currentSum = 0; // 这里在每次计算后需要初始化当前和 26 | } 27 | } 28 | System.out.println("连加值最大的和为" + maxSum); 29 | System.out.print("连加值最大的子数组为:"); 30 | for (int i = start; i <= end; i++) { 31 | System.out.print(array[i]); 32 | if (i != end) { 33 | System.out.print(","); 34 | } 35 | } 36 | System.out.println(); 37 | } 38 | 39 | /** 40 | * 暴力穷举法 41 | * @param array 42 | */ 43 | public static void find2(int[] array) { 44 | int maxSum = array[0]; 45 | int currentSum = 0; 46 | int start = 0; 47 | int end = 0; 48 | for (int i = 0; i < array.length; i++) { 49 | for (int j = i; j < array.length; j++) { 50 | currentSum += array[j]; 51 | // 如果本次的和大于之前累加的最大和,就重新赋值 52 | if (currentSum > maxSum) { 53 | maxSum = currentSum; 54 | start = i; 55 | end = j; 56 | } 57 | } 58 | currentSum = 0; // 这里在每次计算后需要初始化当前和 59 | } 60 | System.out.println("连加值最大的和为" + maxSum); 61 | System.out.print("连加值最大的子数组为:"); 62 | for (int i = start; i <= end; i++) { 63 | System.out.print(array[i]); 64 | if (i != end) { 65 | System.out.print(","); 66 | } 67 | } 68 | System.out.println(); 69 | } 70 | 71 | /** 72 | * 动态规划法 73 | * @param array 74 | */ 75 | public static void find3(int[] array) { 76 | int lastSum = 0; 77 | int maxSum = array[0]; 78 | int start = 0; 79 | int end = 0; 80 | for (int i = 0; i < array.length; i++) { 81 | if (lastSum > 0) { 82 | // 累加 83 | lastSum = lastSum + array[i]; 84 | } else { 85 | // 如果需要新的起点了,重新赋值start 86 | lastSum = array[i]; 87 | start = i; 88 | } 89 | if (maxSum < lastSum) { 90 | // 有新的最大和了 91 | maxSum = lastSum; 92 | end = i; 93 | } 94 | } 95 | System.out.println("连加值最大的和为" + maxSum); 96 | System.out.print("连加值最大的子数组为:"); 97 | for (int i = start; i <= end; i++) { 98 | System.out.print(array[i]); 99 | if (i != end) { 100 | System.out.print(","); 101 | } 102 | } 103 | System.out.println(); 104 | } 105 | 106 | /** 107 | * 获取矩阵的最大和子矩阵 108 | * @param matrix 109 | * @return 110 | */ 111 | public static int maxSumSubMatrix(int[][] matrix) { 112 | int[][] total = matrix; 113 | for (int i = 1; i < matrix.length; i++) { 114 | for (int j = 0; j < matrix[0].length; j++) { 115 | total[i][j] += total[i - 1][j]; 116 | } 117 | } 118 | 119 | int maximum = Integer.MIN_VALUE; 120 | for (int i = 0; i < matrix.length; i++) { 121 | for (int j = i; j < matrix.length; j++) { 122 | // result 保存的是从 i 行 到第 j 行 所对应的矩阵所有元素值的和 123 | int[] result = new int[matrix[0].length]; 124 | for (int l = 0; l < matrix[0].length; l++) { 125 | if (i == 0) { 126 | result[l] = total[j][l]; 127 | } else { 128 | result[l] = total[j][l] - total[i - 1][l]; 129 | } 130 | } 131 | int maximal = maxSubArray(result); 132 | 133 | if (maximal > maximum) { 134 | maximum = maximal; 135 | } 136 | } 137 | } 138 | 139 | return maximum; 140 | } 141 | 142 | /** 143 | * 和find3的动态规划一样 144 | * @param array 145 | * @return 146 | */ 147 | private static int maxSubArray(int[] array) { 148 | int lastSum = 0; 149 | int maxSum = array[0]; 150 | for (int i = 0; i < array.length; i++) { 151 | if (lastSum > 0) { 152 | lastSum = lastSum + array[i]; 153 | } else { 154 | lastSum = array[i]; 155 | } 156 | if (maxSum < lastSum) { 157 | maxSum = lastSum; 158 | } 159 | } 160 | return maxSum; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/MaxSumSubArrayTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class MaxSumSubArrayTest { 4 | 5 | public static void main(String[] args) { 6 | int[] array = {3, -6, 1, 2, 3, -1, 2, -5, 1, 2}; 7 | MaxSumSubArray.find1(array); 8 | MaxSumSubArray.find2(array); 9 | MaxSumSubArray.find3(array); 10 | 11 | int[][] matrix = {{-1, 2, -1, 3, -4}, {2, 3, 4, -5, 1}, {1, -1, 5, -3, -2}}; 12 | System.out.println(MaxSumSubArray.maxSumSubMatrix(matrix)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/RandomArray.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | import java.util.Random; 4 | 5 | public class RandomArray { 6 | 7 | /** 8 | * 随便糊弄一下的解法 9 | * @param array 10 | */ 11 | public static void random1(int[] array) { 12 | Random random = new Random(); 13 | int n = array.length; 14 | for (int i = 0; i < n; i++) { 15 | int j = random.nextInt(n); 16 | int k = random.nextInt(n); 17 | int temp = array[j]; 18 | array[j] = array[k]; 19 | array[k] = temp; 20 | } 21 | System.out.print("随机后结果:"); 22 | for (int i = 0; i < array.length; i++) { 23 | System.out.print(array[i]); 24 | if (i != array.length - 1) { 25 | System.out.print(","); 26 | } 27 | } 28 | System.out.println(); 29 | } 30 | 31 | /** 32 | * 借鉴简单插入排序思想 33 | * @param array 34 | */ 35 | public static void random2(int[] array) { 36 | Random random = new Random(); 37 | // 这里的i每次就是分界指针 38 | for (int i = 0; i < array.length; i++) { 39 | // 在未随机好部分随机获得一个元素下标 40 | int j = random.nextInt(array.length - i) + i; 41 | int temp = array[i]; 42 | array[i] = array[j]; 43 | array[j] = temp; 44 | } 45 | System.out.print("随机后结果:"); 46 | for (int i = 0; i < array.length; i++) { 47 | System.out.print(array[i]); 48 | if (i != array.length - 1) { 49 | System.out.print(","); 50 | } 51 | } 52 | System.out.println(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/RandomArrayTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class RandomArrayTest { 4 | 5 | public static void main(String[] args) { 6 | int[] array1 = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 7 | int[] array2 = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 8 | RandomArray.random1(array1); 9 | RandomArray.random2(array2); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/TwoSum.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | import me.irfen.algorithm.ch01.HashTable; 4 | import me.irfen.algorithm.ch03.QuickSort; 5 | 6 | public class TwoSum { 7 | 8 | /** 9 | * 暴力解法 10 | * @param array 11 | * @param sum 12 | */ 13 | public static void find1(int[] array, int sum) { 14 | for (int i = 0; i < array.length; i++) { 15 | for (int j = 0; j < array.length; j++) { 16 | // 当不是同一个值并且两值之和为sum,输出下标 17 | if (i != j && array[i] == sum - array[j]) { 18 | System.out.println(String.format("i:%d, j:%d", i, j)); 19 | return; 20 | } 21 | } 22 | } 23 | } 24 | 25 | /** 26 | * 散列表实现 27 | * @param array 28 | * @param sum 29 | */ 30 | public static void find2(int[] array, int sum) { 31 | HashTable hashTable = new HashTable(); 32 | // 首先填充散列表 33 | for (int i = 0; i < array.length; i++) { 34 | hashTable.put(array[i], i); 35 | } 36 | // 依次判断对应值是否存在于散列表中 37 | for (int i = 0; i < array.length; i++) { 38 | int index = hashTable.get(sum - array[i]); 39 | if (index != -1 && index != i) { 40 | System.out.println(String.format("i:%d, j:%d", index, i)); 41 | return; 42 | } 43 | } 44 | } 45 | 46 | /** 47 | * 排序双数组法 48 | * @param array 49 | * @param sum 50 | */ 51 | public static void find3(int[] array, int sum) { 52 | // 先快排 53 | QuickSort sort = new QuickSort(array); 54 | sort.sort(); 55 | // 初始化相对数组 56 | int[] array2 = new int[array.length]; 57 | for (int i = 0; i < array.length; i++) { 58 | array2[i] = sum - array[i]; 59 | } 60 | int i = 0; 61 | int j = array2.length - 1; 62 | // i肯定不能大于等于j,不然就判断重复了 63 | while (i < j) { 64 | if (array[i] == array2[j]) { 65 | System.out.println(String.format("i:%d, j:%d", i, j)); 66 | return; 67 | }else if (array[i] < array2[j]) { 68 | while (i < j && array[i] < array2[j]) { 69 | i ++; 70 | } 71 | } else { 72 | while (i < j && array[i] > array2[j]) { 73 | j --; 74 | } 75 | } 76 | } 77 | } 78 | 79 | /** 80 | * 排序单数组法 81 | * @param array 82 | * @param sum 83 | */ 84 | public static void find4(int[] array, int sum) { 85 | // 先快排 86 | QuickSort sort = new QuickSort(array); 87 | sort.sort(); 88 | int i = 0; 89 | int j = array.length - 1; 90 | while (i < j) { 91 | int sumTemp = array[i] + array[j]; 92 | if (sumTemp == sum) { 93 | System.out.println(String.format("i:%d, j:%d", i, j)); 94 | return; 95 | } else if (sumTemp > sum) { 96 | j --; 97 | } else if (sumTemp < sum) { 98 | i ++; 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch08/TwoSumTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch08; 2 | 3 | public class TwoSumTest { 4 | 5 | public static void main(String[] args) { 6 | int[] array = {1, 3, 7, 5, 15, 9}; 7 | int sum = 10; 8 | TwoSum.find1(array, sum); 9 | TwoSum.find2(array, sum); 10 | TwoSum.find3(array, sum); // 其实这里数组已经被排序过了 11 | TwoSum.find4(array, sum); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch09/FindK.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch09; 2 | 3 | public class FindK { 4 | 5 | public static void find(int[] array, int begin, int end, int k) { 6 | int i = partition(array, begin, end); 7 | if (i + 1 > k) { 8 | // 右半部分 9 | find(array, begin, i - 1, k); 10 | } else if (i + 1 < k) { 11 | find(array, i + 1, end, k); 12 | } else { 13 | System.out.println("找到了:" + array[i]); 14 | return; 15 | } 16 | } 17 | 18 | /** 19 | * 每趟快速排序 20 | * @param array 21 | * @param begin 22 | * @param end 23 | * @return 24 | */ 25 | private static int partition(int[] array, int begin, int end) { 26 | if (begin < end) { 27 | int key = array[begin]; 28 | while (begin < end) { 29 | while (begin < end && array[end] > key) { 30 | end--; 31 | } 32 | if (begin < end) { 33 | array[begin] = array[end]; 34 | begin++; 35 | } 36 | while (begin < end && array[begin] < key) { 37 | begin++; 38 | } 39 | if (begin < end) { 40 | array[end] = array[begin]; 41 | end--; 42 | } 43 | } 44 | array[begin] = key; 45 | } 46 | return begin; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch09/FindKTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch09; 2 | 3 | import me.irfen.algorithm.ch08.RandomArray; 4 | 5 | public class FindKTest { 6 | 7 | public static void main(String[] args) { 8 | int[] array = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10, 12, 11, 15, 14, 13}; 9 | RandomArray.random2(array); 10 | FindK.find(array, 0, array.length - 1, 10); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch09/LostNumber.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch09; 2 | 3 | import me.irfen.algorithm.ch01.HashTable; 4 | import me.irfen.algorithm.ch03.QuickSort; 5 | 6 | public class LostNumber { 7 | 8 | /** 9 | * 借助快速排序实现 10 | * @param array 11 | */ 12 | public static void find1(int[] array) { 13 | QuickSort sort = new QuickSort(array); 14 | sort.sort(); 15 | for (int i = 1; i < array.length; i++) { 16 | if (array[i] - array[i - 1] != 1) { 17 | System.out.println("缺失的数字为:" + (array[i] - 1)); 18 | return; 19 | } 20 | } 21 | } 22 | 23 | /** 24 | * 借助快速排序实现 25 | * @param array 26 | */ 27 | public static void find2(int[] array) { 28 | QuickSort sort = new QuickSort(array); 29 | sort.sort(); 30 | for (int i = 1; i < array.length; i++) { 31 | if (array[i] != i + 1) { 32 | System.out.println("缺失的数字为:" + (array[i] - 1)); 33 | return; 34 | } 35 | } 36 | } 37 | 38 | /** 39 | * 借助散列表实现 40 | * @param array 41 | */ 42 | public static void find3(int[] array) { 43 | HashTable hashTable = new HashTable(); 44 | for (int i = 0; i < array.length; i++) { 45 | hashTable.put(array[i], 1); 46 | } 47 | for (int i = 1; i <= 100; i++) { 48 | // 不存在 49 | if (hashTable.get(i) == -1) { 50 | System.out.println("缺失的数字为:" + i); 51 | return; 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * 投机取巧法 58 | * @param array 59 | */ 60 | public static void find4(int[] array) { 61 | int all = (1 + 100) * 100 / 2; 62 | for (int i = 0; i < array.length; i++) { 63 | all -= array[i]; 64 | } 65 | System.out.println("缺失的数字为:" + all); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch09/LostNumberTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch09; 2 | 3 | import me.irfen.algorithm.ch08.RandomArray; 4 | 5 | public class LostNumberTest { 6 | 7 | public static void main(String[] args) { 8 | // 初始化100个数字 9 | int[] arrayOld = new int[100]; 10 | for (int i = 0; i < arrayOld.length; i++) { 11 | arrayOld[i] = i + 1; 12 | } 13 | // 打乱顺序 14 | RandomArray.random2(arrayOld); 15 | // 只填充前99个数,缺失的数字为乱序100个数中最后一个元素 16 | int[] array1 = new int[99]; 17 | int[] array2 = new int[99]; 18 | int[] array3 = new int[99]; 19 | for (int i = 0; i < array1.length; i++) { 20 | array1[i] = arrayOld[i]; 21 | array2[i] = arrayOld[i]; 22 | array3[i] = arrayOld[i]; 23 | } 24 | LostNumber.find1(array1); 25 | LostNumber.find2(array2); 26 | LostNumber.find3(array3); 27 | LostNumber.find4(array3); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch09/MoreThanHalf.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch09; 2 | 3 | import me.irfen.algorithm.ch01.HashTable; 4 | import me.irfen.algorithm.ch03.QuickSort; 5 | 6 | public class MoreThanHalf { 7 | 8 | /** 9 | * 排序解法 10 | * @param array 11 | */ 12 | public static void find1(int[] array) { 13 | QuickSort quickSort = new QuickSort(array); 14 | quickSort.sort(); 15 | int count = 1; // 初始化为1,因为下面要忽略第一个元素开始累加 16 | // 这里从下标为1的元素开始 17 | for (int i = 1; i < array.length; i++) { 18 | // 如果不相同的话需要进行判断 19 | if (array[i] != array[i - 1]) { 20 | // 如果大于一半次数 21 | if (count > array.length / 2) { 22 | System.out.println("找到了,这个元素为" + array[i - 1]); 23 | return; 24 | } else { 25 | count = 1; // 重置为1,因为要把自己这次加上 26 | } 27 | } else { 28 | // 如果相同需要累加 29 | count++; 30 | } 31 | } 32 | if (count > array.length / 2) { 33 | // 如果遍历到最后,都是相同的,并且大于一半 34 | //说明最后的元素就是要找的元素 35 | System.out.println("找到了,这个元素为" + array[array.length - 1]); 36 | } else { 37 | // 说明这个数组中就没有元素出现次数超过一半 38 | System.out.println("没有找到"); 39 | } 40 | } 41 | 42 | /** 43 | * 借助散列表查找 44 | * @param array 45 | */ 46 | public static void find2(int[] array) { 47 | // 如果数组元素只有一个的话, 48 | if (array.length == 1) { 49 | System.out.println("找到了,这个元素为" + array[0]); 50 | return; 51 | } 52 | HashTable hashTable = new HashTable(); 53 | for (int i = 0; i < array.length; i++) { 54 | int count = hashTable.get(array[i]); 55 | if (count > 0) { 56 | count ++; 57 | // 说明存在,如果达成条件直接输出 58 | if (count > array.length / 2) { 59 | System.out.println("找到了,这个元素为" + array[i]); 60 | return; 61 | } 62 | hashTable.put(array[i], count); 63 | } else { 64 | hashTable.put(array[i], 1); 65 | } 66 | } 67 | System.out.println("没有找到"); 68 | } 69 | 70 | /** 71 | * O(n)时间复杂度解法 72 | * @param array 73 | */ 74 | public static void find3(int[] array) { 75 | int t = array[0]; 76 | int n = 0; 77 | for (int i = 0; i < array.length; i++) { 78 | if (array[i] == t) { 79 | n ++; 80 | } else { 81 | n --; 82 | } 83 | if (n == 0) { 84 | t = array[i]; 85 | n = 1; 86 | } 87 | } 88 | System.out.println("找到了,这个元素为" + t); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch09/MoreThanHalfTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch09; 2 | 3 | public class MoreThanHalfTest { 4 | 5 | public static void main(String[] args) { 6 | int[] array1 = {0, 1, 2, 1, 2, 1, 1}; 7 | int[] array2 = {0, 2, 2, 1, 2, 0, 2}; 8 | MoreThanHalf.find1(array1); 9 | MoreThanHalf.find1(array2); 10 | 11 | int[] array3 = {0, 1, 2, 1, 2, 1, 1}; 12 | int[] array4 = {0, 2, 2, 1, 2, 0, 2}; 13 | MoreThanHalf.find2(array3); 14 | MoreThanHalf.find2(array4); 15 | 16 | MoreThanHalf.find3(array3); 17 | MoreThanHalf.find3(array4); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch11/ArrayList.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch11; 2 | 3 | import java.util.Arrays; 4 | 5 | public class ArrayList { 6 | 7 | /** 8 | * 默认初始化数组长度 9 | */ 10 | private static final int INITIAL_CAPACITY = 10; 11 | 12 | private int size = 0; 13 | 14 | private Object[] array; 15 | 16 | public ArrayList() { 17 | this(INITIAL_CAPACITY); 18 | } 19 | 20 | public ArrayList(int initial) { 21 | if (initial <= 0) { 22 | throw new RuntimeException("初始化变长数组空间错误"); 23 | } 24 | array = new Object[initial]; 25 | } 26 | 27 | /** 28 | * 添加元素 29 | * @param o 30 | */ 31 | public void add(Object o) { 32 | ensureCapacityHelper(size + 1); 33 | array[size++] = o; 34 | } 35 | 36 | /** 37 | * 获取指定位置的元素值 38 | * @param i 39 | * @return 40 | */ 41 | public T get(int i) { 42 | rangeCheck(i); 43 | return elementData(i); 44 | } 45 | 46 | /** 47 | * 设置指定位置的元素值 48 | * @param i 49 | * @param o 50 | * @return 51 | */ 52 | public T set(int i, Object o) { 53 | rangeCheck(i); 54 | T old = elementData(i); 55 | array[i] = o; 56 | return old; 57 | } 58 | 59 | /** 60 | * 删除指定下标元素(后面元素需要前移) 61 | * @param i 62 | * @return 63 | */ 64 | public T remove(int i) { 65 | rangeCheck(i); 66 | // 要删除的元素 67 | T old = elementData(i); 68 | // 需要移动的元素数量 69 | int numMoved = size - i - 1; 70 | if (numMoved > 0) { 71 | // 调用系统函数前移移动元素所有后面的元素 72 | System.arraycopy(array, i + 1, array, i, numMoved); 73 | } 74 | // 强迫症可以把移出来的空间置空(其实这个空间还好) 75 | // 这里注意一定要把size减1 76 | array[--size] = null; 77 | return old; 78 | } 79 | 80 | /** 81 | * 清空数组 82 | */ 83 | public void clear() { 84 | // 清空所有元素值(不清问题也不大) 85 | for (int i = 0; i < size; i++) { 86 | array[i] = null; 87 | } 88 | // size置为0 89 | size = 0; 90 | } 91 | 92 | /** 93 | * 获取指定元素下标,不存在返回-1 94 | * @param o 95 | * @return 96 | */ 97 | public int indexOf(Object o) { 98 | if (o == null) { 99 | for (int i = 0; i < size; i++) { 100 | if (array[i]==null) { 101 | return i; 102 | } 103 | } 104 | } else { 105 | for (int i = 0; i < size; i++) { 106 | if (o.equals(array[i])) { 107 | return i; 108 | } 109 | } 110 | } 111 | return -1; 112 | } 113 | 114 | /** 115 | * 判断指定元素是否存在与数组中 116 | * @param o 117 | * @return 118 | */ 119 | public boolean contains(Object o) { 120 | return indexOf(o) >= 0; 121 | } 122 | 123 | public T getFirst() { 124 | return get(0); 125 | } 126 | 127 | public T getLast() { 128 | return get(size - 1); 129 | } 130 | 131 | /** 132 | * 获取变长数组的长度 133 | * @return 134 | */ 135 | public int size() { 136 | return size; 137 | } 138 | 139 | /** 140 | * 是否为空 141 | * @return 142 | */ 143 | public boolean isEmpty() { 144 | return size == 0; 145 | } 146 | 147 | /** 148 | * 确保空间够用 149 | * @param minCapacity 150 | */ 151 | private void ensureCapacityHelper(int minCapacity) { 152 | if (minCapacity > array.length) { 153 | // 说明需要的空间不够了 154 | grow(); 155 | } 156 | } 157 | 158 | /** 159 | * 涨空间 160 | */ 161 | private void grow() { 162 | int oldCapacity = array.length; 163 | int newCapacity = oldCapacity * 2; 164 | if (newCapacity < oldCapacity) { 165 | // 说明溢出了 166 | throw new OutOfMemoryError(); 167 | } else { 168 | array = Arrays.copyOf(array, newCapacity); 169 | } 170 | } 171 | 172 | /** 173 | * 确认指定下标是否符合数组实际长度 174 | * @param index 175 | */ 176 | private void rangeCheck(int index) { 177 | if (index >= size) 178 | throw new IndexOutOfBoundsException("当前下标不存在"); 179 | } 180 | 181 | /** 182 | * 获取指定下标元素 183 | * 这里强制转型一次就好了 184 | * @param index 185 | * @return 186 | */ 187 | private T elementData(int index) { 188 | return (T) array[index]; 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch11/ArrayListTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch11; 2 | 3 | public class ArrayListTest { 4 | 5 | public static void main(String[] args) { 6 | ArrayList list = new ArrayList(); 7 | list.add("a"); 8 | list.add("b"); 9 | list.add("c"); 10 | System.out.println(list.indexOf("a")); 11 | System.out.println(list.contains("a")); 12 | System.out.println(list.get(1)); 13 | System.out.println(list.getFirst()); 14 | System.out.println(list.getLast()); 15 | list.clear(); 16 | System.out.println(list.isEmpty()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch11/HashMap.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch11; 2 | 3 | import java.util.Arrays; 4 | 5 | public class HashMap { 6 | 7 | /** 8 | * 默认散列表初始化长度(16) 9 | */ 10 | private static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 11 | 12 | /** 13 | * 默认扩容因子 14 | */ 15 | private static final float DEFAULT_LOAD_FACTOR = 0.75f; 16 | 17 | /** 18 | * 散列表数组 19 | */ 20 | private Entry[] table; 21 | 22 | /** 23 | * 扩容因子 24 | */ 25 | final float loadFactor; 26 | 27 | private int size = 0; // 散列表元素个数 28 | private int use = 0; // 散列表使用数组元素数 29 | 30 | 31 | public HashMap() { 32 | this(DEFAULT_INITIAL_CAPACITY); 33 | } 34 | 35 | public HashMap(int initCapacity) { 36 | this(initCapacity, DEFAULT_LOAD_FACTOR); 37 | } 38 | 39 | public HashMap(int initCapacity, float loadFactor) { 40 | this.table = new Entry[initCapacity]; 41 | this.loadFactor = loadFactor; 42 | } 43 | 44 | /** 45 | * 添加/修改 46 | * 47 | * @param key 48 | * @param value 49 | */ 50 | public void put(K key, V value) { 51 | int index = hash(key); 52 | Entry e = table[index]; 53 | if (e == null) { 54 | // 不存在值,向链表添加,有可能需要扩容 55 | table[index] = new Entry(key, value, null); 56 | size++; 57 | use++; 58 | // 不存在值,说明是个未用过的地址,需要判断是否需要扩容 59 | // 其实这里可以使用size判断,可以保持某一个数组元素下的链表不要太长 60 | if (use >= table.length * loadFactor) { 61 | resize(); 62 | } 63 | } else { 64 | // 本身存在值,修改已有的值 65 | for (; e != null; e = e.next) { 66 | Object k = e.key; 67 | if (k == key || k.equals(key)) { 68 | e.value = value; 69 | return; 70 | } 71 | } 72 | // 不存在相同的值,直接往链表添加元素 73 | Entry temp = table[index]; 74 | Entry newEntry = new Entry(key, value, temp); 75 | table[index] = newEntry; 76 | size++; 77 | } 78 | } 79 | 80 | /** 81 | * 删除 82 | * 83 | * @param key 84 | */ 85 | public void remove(K key) { 86 | int index = hash(key); 87 | Entry e = table[index]; 88 | Entry pre = null; 89 | for (; e != null; pre = e, e = e.next) { 90 | K k = e.key; 91 | if (k == key || k.equals(key)) { 92 | if (pre == null) { 93 | // 说明删除的是第一个元素 94 | table[index] = null; 95 | } else { 96 | pre.next = e.next; 97 | size--; 98 | } 99 | return; 100 | } 101 | } 102 | } 103 | 104 | /** 105 | * 获取 106 | * 107 | * @param key 108 | * @return 109 | */ 110 | public V get(K key) { 111 | int index = hash(key); 112 | Entry e = table[index]; 113 | for (; e != null; e = e.next) { 114 | Object k = e.key; 115 | if (k == key || k.equals(key)) { 116 | return e.value; 117 | } 118 | } 119 | // 没有找到返回null 120 | return null; 121 | } 122 | 123 | /** 124 | * 想想这里为什么不直接get之后判断是否为空呢 125 | * @param key 126 | * @return 127 | */ 128 | public boolean containsKey(K key) { 129 | int index = hash(key); 130 | Entry e = table[index]; 131 | for (; e != null; e = e.next) { 132 | Object k = e.key; 133 | if (k == key || k.equals(key)) { 134 | return true; 135 | } 136 | } 137 | return false; 138 | } 139 | 140 | /** 141 | * 清空散列表 142 | */ 143 | public void clear() { 144 | Arrays.fill(table, null); 145 | size = 0; 146 | use = 0; 147 | } 148 | 149 | /** 150 | * 获取散列表中元素个数 151 | * 152 | * @return 153 | */ 154 | public int size() { 155 | return size; 156 | } 157 | 158 | public boolean isEmpty() { 159 | return size == 0; 160 | } 161 | 162 | /** 163 | * 根据key,通过哈希函数获取位于散列表数组中的哪个位置 164 | * 165 | * @param key 166 | * @return 167 | */ 168 | private int hash(K key) { 169 | int hashCode = Math.abs(key.hashCode()); 170 | hashCode %= table.length; 171 | return hashCode; 172 | } 173 | 174 | /** 175 | * 扩容 176 | */ 177 | private void resize() { 178 | int newLength = table.length * 2; 179 | Entry[] oldTable = table; 180 | table = new Entry[newLength]; 181 | use = 0; 182 | for (int i = 0; i < oldTable.length; i++) { 183 | Entry e = oldTable[i]; 184 | while (null != e) { 185 | // 重新计算哈希值,放入新的地址中 186 | int index = hash(e.key); 187 | if (table[index] == null) { 188 | use++; 189 | table[index] = new Entry(e.key, e.value, null); 190 | } else { 191 | Entry temp = table[index]; 192 | Entry newEntry = new Entry(e.key, e.value, temp); 193 | table[index] = newEntry; 194 | } 195 | e = e.next; 196 | } 197 | } 198 | } 199 | 200 | static class Entry { 201 | K key; 202 | V value; 203 | Entry next; 204 | 205 | Entry(K key, V value, Entry next) { 206 | this.key = key; 207 | this.value = value; 208 | this.next = next; 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch11/HashMapTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch11; 2 | 3 | public class HashMapTest { 4 | 5 | public static void main(String[] args) { 6 | HashMap map = new HashMap(2); 7 | map.put("a", "A"); 8 | map.put("b", "B"); 9 | map.put("c", "C"); 10 | map.put("d", "D"); 11 | map.put("e", "E"); 12 | map.put("f", "F"); 13 | map.put("g", "G"); 14 | 15 | System.out.println(map.get("a")); 16 | System.out.println(map.get("b")); 17 | System.out.println(map.get("c")); 18 | System.out.println(map.get("d")); 19 | System.out.println(map.get("e")); 20 | System.out.println(map.get("f")); 21 | System.out.println(map.get("g")); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch11/Stack.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch11; 2 | 3 | import java.util.Arrays; 4 | 5 | public class Stack { 6 | 7 | private int size = 0; 8 | private Object[] array; 9 | 10 | /** 11 | * 默认初始化栈 12 | */ 13 | public Stack() { 14 | this(10); 15 | } 16 | 17 | /** 18 | * 指定栈空间初始化 19 | * @param initialCapacity 20 | */ 21 | public Stack(int initialCapacity) { 22 | if (initialCapacity <= 0) { 23 | throw new RuntimeException("初始化栈空间错误"); 24 | } 25 | array = new Object[initialCapacity]; 26 | } 27 | 28 | /** 29 | * 入栈 30 | * @param item 31 | * @return 32 | */ 33 | public E push(E item) { 34 | ensureCapacityHelper(size + 1); 35 | array[size++] = item; 36 | return item; 37 | } 38 | 39 | /** 40 | * 获取栈顶元素,但是没有出栈 41 | * @return 42 | */ 43 | public E peek() { 44 | if (isEmpty()) { 45 | throw new IndexOutOfBoundsException("栈里已经空啦"); 46 | } 47 | return (E) array[size - 1]; 48 | } 49 | 50 | /** 51 | * 出栈,同时获取栈顶元素 52 | * @return 53 | */ 54 | public E pop() { 55 | E item = peek(); 56 | size --; // 直接使元素个数减1,不需要真的清除元素,下次入栈会覆盖旧元素值 57 | return item; 58 | } 59 | 60 | /** 61 | * 栈是否为空栈 62 | * @return 63 | */ 64 | public boolean isEmpty() { 65 | return size == 0; 66 | } 67 | 68 | public int size() { 69 | return size; 70 | } 71 | 72 | /** 73 | * 确保空间够用 74 | * @param minCapacity 75 | */ 76 | private void ensureCapacityHelper(int minCapacity) { 77 | if (minCapacity > array.length) { 78 | // 说明需要的空间不够了 79 | grow(); 80 | } 81 | } 82 | 83 | /** 84 | * 涨空间 85 | */ 86 | private void grow() { 87 | int oldCapacity = array.length; 88 | int newCapacity = oldCapacity * 2; 89 | if (newCapacity < oldCapacity) { 90 | // 说明溢出了 91 | throw new OutOfMemoryError(); 92 | } else { 93 | array = Arrays.copyOf(array, newCapacity); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/me/irfen/algorithm/ch11/StackTest.java: -------------------------------------------------------------------------------- 1 | package me.irfen.algorithm.ch11; 2 | 3 | public class StackTest { 4 | 5 | public static void main(String[] args) { 6 | Stack s = new Stack(); 7 | s.push("a"); 8 | s.push("b"); 9 | System.out.println(s.pop()); 10 | System.out.println(s.peek()); 11 | } 12 | } 13 | --------------------------------------------------------------------------------