Skip to content

Commit 35c5dfe

Browse files
committed
常用数据结构及其算法(Java)
0 parents  commit 35c5dfe

10 files changed

Lines changed: 701 additions & 0 deletions

File tree

.classpath

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<classpath>
3+
<classpathentry kind="src" path="src"/>
4+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
5+
<classpathentry kind="output" path="bin"/>
6+
</classpath>

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/bin/

.project

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>DataStructure</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.jdt.core.javabuilder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>org.eclipse.jdt.core.javanature</nature>
16+
</natures>
17+
</projectDescription>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
eclipse.preferences.version=1
2+
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3+
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
4+
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5+
org.eclipse.jdt.core.compiler.compliance=1.7
6+
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7+
org.eclipse.jdt.core.compiler.debug.localVariable=generate
8+
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9+
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10+
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11+
org.eclipse.jdt.core.compiler.source=1.7
Lines changed: 351 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,351 @@
1+
package cn.edu.tju.rico.list;
2+
3+
/**
4+
* Title: 链表的Java实现
5+
* Description: 链表结构包含两个要素: 头结点head + 链表大小size,操作包括:
6+
* 链表的增删
7+
* 链表是否为空
8+
* 链表的大小
9+
* 链表的打印输出
10+
* 删除链表重复节点
11+
* 链表倒数第K个元素
12+
* 链表的反转
13+
* 链表的倒序输出
14+
* 链表的中间节点
15+
* 链表是否有环
16+
* 链表节点的删除(不知道头结点的情况下)
17+
* 链表是否相交
18+
* 链表的交点
19+
*
20+
* @author rico
21+
*/
22+
public class LinkedList<E> {
23+
24+
private Node<E> head; // 链表表头
25+
private int size; // 链表大小
26+
27+
public LinkedList() {
28+
head = new Node<E>(null);
29+
}
30+
31+
public Node<E> getHead() {
32+
return head;
33+
}
34+
35+
/**
36+
* @description 向链表中指定位置的元素(0 - size),返回新节点
37+
* @author rico
38+
* @param data
39+
* @param index
40+
* @throws Exception
41+
*/
42+
public Node<E> add(E data, int index) throws Exception {
43+
if (index > size) {
44+
throw new Exception("超出范围...");
45+
}
46+
47+
Node<E> cur = head;
48+
for (int i = 0; i < index; i++) {
49+
cur = cur.next;
50+
}
51+
Node<E> node = new Node<E>(data); // 将新元素链入链表
52+
cur.next = node;
53+
size++;
54+
return node;
55+
}
56+
57+
/**
58+
* @description 向链表末尾添加元素,返回新节点
59+
* @author rico
60+
* @param data
61+
* @throws Exception
62+
*/
63+
public Node<E> add(E data) throws Exception {
64+
return add(data, size);
65+
}
66+
67+
/**
68+
* @description 向链表尾部添加新节点
69+
* @author rico
70+
* @param node
71+
*/
72+
public void add(Node<E> node){
73+
Node<E> cur = head;
74+
while(cur.next != null){
75+
cur = cur.next;
76+
}
77+
cur.next = node;
78+
79+
while(node != null){
80+
size ++;
81+
node = node.next;
82+
}
83+
}
84+
85+
/**
86+
* @description 删除链表中指定位置的元素(0 ~ size-1)
87+
* @author rico
88+
* @param index
89+
* @return
90+
* @throws Exception
91+
*/
92+
public E remove(int index) throws Exception {
93+
if (index > size - 1 || index < 0) {
94+
throw new Exception("超出范围...");
95+
}
96+
97+
Node<E> cur = head;
98+
for (int i = 0; i < index; i++) {
99+
cur = cur.next;
100+
}
101+
102+
Node<E> temp = cur.next;
103+
cur.next = temp.next;
104+
temp.next = null;
105+
106+
size--;
107+
return temp.data;
108+
}
109+
110+
/**
111+
* @description 向链表末尾删除元素
112+
* @author rico
113+
* @return
114+
* @throws Exception
115+
*/
116+
public E remove() throws Exception {
117+
return remove(size - 1);
118+
}
119+
120+
/**
121+
* @description 删除链表中的重复元素(外循环 + 内循环)
122+
* @author rico 时间复杂度:O(n^2)
123+
*/
124+
public void removeDuplicateNodes() {
125+
Node<E> cur = head.next;
126+
while (cur != null) { // 外循环
127+
Node<E> temp = cur;
128+
while (temp != null && temp.next != null) { // 内循环
129+
if (cur.data.equals(temp.next.data)) {
130+
Node<E> duplicateNode = temp.next;
131+
temp.next = duplicateNode.next;
132+
duplicateNode.next = null;
133+
size --;
134+
}
135+
temp = temp.next;
136+
}
137+
cur = cur.next;
138+
}
139+
}
140+
141+
/**
142+
* @description 找出单链表中倒数第K个元素(双指针法,相差K-1步)
143+
* @author rico
144+
* @param k
145+
* @return 时间复杂度:O(n)
146+
*/
147+
public Node<E> getEndK(int k) {
148+
Node<E> pre = head.next;
149+
Node<E> post = head.next;
150+
for (int i = 1; i < k; i++) { // pre先走k-1步
151+
if (pre != null) {
152+
pre = pre.next;
153+
}
154+
}
155+
if (pre != null) {
156+
// 当pre走到链表末端时,post正好指向倒数第K个节点
157+
while (pre != null && pre.next != null) {
158+
pre = pre.next;
159+
post = post.next;
160+
}
161+
return post;
162+
}
163+
return null;
164+
}
165+
166+
/**
167+
* @description 反转链表
168+
* @author rico
169+
*/
170+
public void reverseLinkedList() {
171+
Node<E> cur = head.next; // 原链表
172+
Node<E> pre = null; // 反转后的链表
173+
174+
while (cur != null) { // 对原链表中的每个节点进行反转
175+
Node<E> next = cur.next; // 记录当前节点的下一个节点
176+
cur.next = pre; // 当前节点指向反转后的链表
177+
pre = cur; // 更新反转后的链表
178+
cur = next; // 更新当前节点
179+
}
180+
head.next = pre; // 将原链表的头结点指向反转后的链表
181+
}
182+
183+
/**
184+
* @description 判断单链表是否为空
185+
* @author rico
186+
* @return
187+
*/
188+
public boolean isEmpty() {
189+
return size == 0;
190+
}
191+
192+
/**
193+
* @description 打印输出单链表
194+
* @author rico
195+
*/
196+
public void print() {
197+
Node<E> cur = head.next;
198+
while (cur != null) {
199+
System.out.print(cur.data + " ");
200+
cur = cur.next;
201+
}
202+
System.out.println();
203+
}
204+
205+
/**
206+
* @description 从尾到头输出单链表(递归法)
207+
* @author rico
208+
* @param head
209+
*/
210+
public void reversePrint(Node<E> head) {
211+
if (head.next != null) {
212+
reversePrint(head.next); // 不断"递去"
213+
System.out.print(head.next.data + " "); // "归来"开始打印
214+
}
215+
}
216+
217+
/**
218+
* @description 寻找单链表中的中间节点(双指针法)
219+
* @author rico
220+
*/
221+
public void printMiddleNodes() {
222+
Node<E> index1 = head.next; // 慢指针
223+
Node<E> index2 = head.next; // 快指针
224+
if (head.next == null) {
225+
System.out.println(index1.data);
226+
}
227+
while (index2 != null && index2.next != null
228+
&& index2.next.next != null) {
229+
index1 = index1.next;
230+
index2 = index2.next.next;
231+
}
232+
System.out.print(index1.data); // 第一个中间节点
233+
if (index2.next != null) { // 当链表长度为偶数时,打印第二个中间节点
234+
System.out.println(index1.next.data);
235+
}
236+
}
237+
238+
/**
239+
* @description 判断单链表是否有环(双指针法)
240+
* @author rico
241+
* @return
242+
*/
243+
public boolean hasLoop() {
244+
Node<E> index1 = head.next; // 慢指针
245+
Node<E> index2 = head.next; // 快指针
246+
while (index2 != null && index2.next != null
247+
&& index2.next.next != null) {
248+
index1 = index1.next;
249+
index2 = index2.next.next;
250+
if (index1 == index2) {
251+
return true;
252+
}
253+
}
254+
return false;
255+
}
256+
257+
/**
258+
* @description 在不知道头结点的前提下,删除指定节点
259+
* @author rico
260+
* @param node
261+
* @return
262+
*/
263+
public boolean deleteNodeWithoutHead(Node<E> node) {
264+
if (node == null || node.next == null) { // 当指定节点为空或者为尾节点时,无法删除
265+
return false;
266+
}
267+
268+
Node<E> next = node.next;
269+
270+
// 将后继节点的内容复制到当前节点
271+
node.data = next.data;
272+
node.next = next.next;
273+
274+
// 将后继节点清空
275+
next.next = null;
276+
next.data = null;
277+
return true;
278+
}
279+
280+
/**
281+
* @description 判断当前链表与目标链表是否相交(相交与否取决于尾节点是否相同)
282+
* @author rico
283+
* @param head
284+
* @return
285+
*/
286+
public boolean isIntersect(LinkedList<E> list2) {
287+
Node<E> cur1 = head.next; // 当前链表
288+
Node<E> cur2 = list2.getHead().next; // 目标链表
289+
290+
// 两链表有一个为空,则返回 false
291+
if(cur1 == null || cur2 == null){
292+
return false;
293+
}
294+
295+
// 遍历到第一个链表的尾节点
296+
while(cur1.next != null){
297+
cur1 = cur1.next;
298+
}
299+
300+
// 遍历到第二个链表的尾节点
301+
while(cur2.next != null){
302+
cur2 = cur2.next;
303+
}
304+
305+
return cur1 == cur2; // 相交与否取决于尾节点是否相同
306+
}
307+
308+
/**
309+
* @description 返回两链表的交点(若不相交,返回null)
310+
* @author rico
311+
* @param head
312+
* @return
313+
*/
314+
public Node<E> getIntersectionPoint(LinkedList<E> list2) {
315+
Node<E> cur1 = head.next; // 当前链表
316+
Node<E> cur2 = list2.getHead().next; // 目标链表
317+
318+
if(this.isIntersect(list2)){ // 先判断是否相交
319+
// 让长度较长的链表先移动step步
320+
int step = Math.abs(list2.size - this.size);
321+
if(list2.size > this.size){
322+
while(step > 0){
323+
cur2 = cur2.next;
324+
step --;
325+
}
326+
}else if(list2.size < this.size){
327+
while(step > 0){
328+
cur1 = cur1.next;
329+
step --;
330+
}
331+
}
332+
333+
//两个指针同时移动,一旦指向同一个节点,即为交点
334+
while(cur1 != cur2){
335+
cur1 = cur1.next;
336+
cur2 = cur2.next;
337+
}
338+
return cur1;
339+
}
340+
return null;
341+
}
342+
343+
/**
344+
* @description 返回链表的长度
345+
* @author rico
346+
* @return
347+
*/
348+
public int size(){
349+
return size;
350+
}
351+
}

0 commit comments

Comments
 (0)