0

Java链表实现

 2 years ago
source link: https://blog.ixk.me/post/java-linked-list-implementation
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Java链表实现

2018-11-29 • Otstar Lin •
本文最后更新于 268 天前,文中所描述的信息可能已发生改变

转换阵营 ing,大部分的介绍都在注释写了,这里就不再重复了,注释中没有关于链表的原理,如果还不懂链表的可以先去看其他教程,这里不写主要是我比较懒( ̄ ▽  ̄)”

[alert-success]之前的算法有问题,现在已经修改完成,并重写了部分代码,对数据域使用泛型,可以存放任何对象了,存放不同数据类型时就不再需要定义多个链表类了ヾ(≧▽≦*)o[/alert-success]

[alert-note]这个算法还有优化的空间,不久后将升级,心急的可以看 C 链表重置版然后将其改成 Java 即可[/alert-note]

1package MyLinkedListDemo;
2
3import java.util.Scanner;
4
5public class MyLinkedListDemo {
6    public static void main(String[] args) {
7        Scanner in = new Scanner(System.in);
8        MyLinkedList<Integer> list = new MyLinkedList<Integer>();
9        list.add(-1, 1);
10        list.add(-1, 2);
11        list.add(-1, 3);
12        list.add(-1, 4);
13        list.add(-1, 5);
14        int a = list.get(2);
15        System.out.println(a);
16        in.close();
17        }
18    }
19
20    class MyLinkedList<T> {
21
22        //链表总长度
23        int len = 0;
24        // 头节点
25        Node head = null;
26        // 尾节点
27        Node end = null;
28
29        // 链表节点类(内部类)
30        class Node {
31            // 上一个节点
32            Node prev;
33            // 下一个节点
34            Node next;
35            // 数据块
36            T data;
37
38            // 空构造器,用于构造临时节点和定位节点等不需要使用数据块的节点
39            Node() {
40            };
41
42            // 可填入数据的构造器,用填入数据
43            Node(T data) {
44                // 填入数据到数据块
45                this.data = data;
46            }
47        }
48
49        // 插入链表节点的方法
50        // 参数i : 表示要插入的位置,当 i = -1 时新节点会被放置头位置,若 i = -2 时新节点会被放置至尾位置
51        public void add(int i /* 要添加的位置,新节点会添加至该位置之后 */, T data /* 传入数据 */) {
52            // 递增定位
53            len++;
54            int j;
55            // 定义定位节点
56            Node indexNode = head;
57            // 创建新节点
58            Node newNode = new Node(data);
59
60            // 判断链表是否为空
61            if (head == null) {
62                // 若是只需将新节点设为头节点和尾节点就行
63                head = newNode;
64                end = newNode;
65                return;
66            }
67
68            // Create Mode
69            if (i == -1) // 头插法
70            {
71                newNode.next = head;
72                head.prev = newNode;
73                head = newNode;
74                return;
75            } else if (i == -2) // 尾插法
76            {
77                while (indexNode.next != null) {
78                    indexNode = indexNode.next;
79                }
80            }
81
82            // Insert Mode
83
84            // 移动定位节点至指定位置
85            for (j = 0; j < i && indexNode != null; j++) {
86                indexNode = indexNode.next;
87            }
88            // 判断是否是添加至最后一个节点
89            if (indexNode.next == null) {
90                // 将上一个节点next指向新节点
91                indexNode.next = newNode;
92                // 将新节点的prev指向上一个节点
93                newNode.prev = indexNode;
94                // 将新节点的next指向null
95                newNode.next = null;
96                // 将新节点设为尾节点
97                end = newNode;
98                return;
99            }
100            // 创建临时节点用于存储原下一个节点的地址
101            Node tempNode = indexNode.next;
102            // 将上一个节点的next指向新节点
103            indexNode.next = newNode;
104            // 将新节点的next指向原下一个节点
105            newNode.next = tempNode;
106            // 将新节点的prev指向上一个节点
107            newNode.prev = indexNode;
108            // 将原下一个节点的prev指向新节点
109            tempNode.prev = newNode;
110        }
111
112        // 插入带数据的链表到指定位置,操作方式同add,只是新增的节点是已经有数据的
113        public void add(int i, Node haveNode) {
114            len++;
115            int j;
116            Node indexNode = head;
117
118            if (i == -1) {
119                haveNode.next = head;
120                head.prev = haveNode;
121                head = haveNode;
122                return;
123            }
124
125            for (j = 0; j < i && indexNode != null; j++) {
126                indexNode = indexNode.next;
127            }
128
129            if (indexNode.next == null) {
130                indexNode.next = haveNode;
131                haveNode.prev = indexNode;
132                haveNode.next = null;
133                end = haveNode;
134                return;
135            }
136
137            haveNode.next = indexNode.next;
138            haveNode.next.prev = haveNode;
139            haveNode.prev = indexNode;
140            indexNode.next = haveNode;
141        }
142
143        // 删除指定节点
144        // 参数 i : 当 i = 0 时代表删除第一个节点,i = -1 时代表删除最后一个节点
145        public void delete(int i/* 要删除节点的位置 */) {
146            len--;
147            // 判断是否是删除第一个节点
148            if (i == 0) {
149                // 将头节点指向第二个节点,然后将头节点的prev设置为null,这样就屏蔽掉了第一个节点
150                head = head.next;
151                head.prev = null;
152                return;
153            }
154            // 若是删除最后一个节点,那只需将尾节点移到倒数第二个节点即可
155            else if (i == -1) {
156                end = end.prev;
157                end.next = null;
158                return;
159            }
160
161            // 递增定位
162            int j;
163            // 创建定位节点,将其指向头节点
164            Node indexNode = head;
165            // 将定位节点移至要删除节点的上一个节点
166            for (j = 0; j < i - 1 && indexNode != null; j++) {
167                indexNode = indexNode.next;
168            }
169            // 判断要删除节点是否是最后一个节点
170            if (indexNode.next.next == null) {
171                // 操作方式同删除头节点与
172                end = end.prev;
173                end.next = null;
174                return;
175            }
176            // 要删除节点的下一个节点prev设置为要删除节点的上一个节点
177            indexNode.next.next.prev = indexNode;
178            // 将要删除节点的上一个节点的next设置为要删除节点的下一个节点
179            indexNode.next = indexNode.next.next;
180        }
181
182        // 清空链表
183        public void clear() {
184            len = 0;
185            // 清空链表只需将头节点和尾节点设置为null即可,内存会由垃圾回收器回收
186            head = null;
187            end = null;
188        }
189
190        // 遍历输出链表数据
191        public void print() {
192            // 创建定位节点
193            Node indexNode = head;
194            // 使用while循环进行遍历
195            while (indexNode != null) {
196                // 输出数据
197                System.out.print(indexNode.data.toString() + " ");
198                // 移动定位节点
199                indexNode = indexNode.next;
200            }
201            // 换行
202            System.out.println();
203        }
204
205        // 链表逆置
206        public void resever() {
207            // 创建临时节点用来临时存储指向数据
208            Node tempNode = new Node();
209            // 将头节点与尾节点交换
210            tempNode = head;
211            head = end;
212            end = tempNode;
213            // 创建定位节点
214            Node indexNode = head;
215            // 循环交换next和prev数据
216            while (indexNode.prev != null && (indexNode.next != null || indexNode == head)) {
217                tempNode = indexNode.next;
218                indexNode.next = indexNode.prev;
219                indexNode.prev = tempNode;
220                indexNode = indexNode.next;
221            }
222            // 设置最后一个节点的next为null
223            end.next = null;
224            // 设置最后一个节点的prev数据
225            end.prev = tempNode.next;
226        }
227
228        // 添加新节点到列表末尾
229        public void addFirst(T data) {
230            this.add(-2, data);
231        }
232
233        // 添加新节点到列表头
234        public void addLast(T data) {
235            this.add(-1, data);
236        }
237
238        // 获取指定位置的数据
239        public T get(int i) {
240            Node indexNode = head;
241            for (int j = 0; j < i; j++) {
242                indexNode = indexNode.next;
243            }
244            return indexNode.data;
245        }
246
247    }

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK