├── .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 |
--------------------------------------------------------------------------------