数据结构 实现单向链表
数据结构对于一个程序员来说是必备的知识,虽然之前也了解过这些数据结构,但是总感觉没有达到一个对所有数据结构都了如指掌的境界,于是作者打算手写实现各种数据结构,以便于学习了解这些数据结构的全貌。
对于数据结构的分析如果足够深入,那么必定还要涉及jvm的内存层面,目前本人还没有足够的知识储备,所以只从代码的层面学习理解这些数据结构的实现。
这次先从最简单的单向链表的实现作为开始,单向链表属于最基础的链表结构,它的定义:链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。——来自百度百科的介绍
链表结构示意图
用我自己的理解来说,链表就是一个个带链接的节点组成的,每个节点由两部分组成,第一部分是该节点存储的数据,第二部分是该节点的下一个节点的指针。这样的结构我们只需要知道这个链表的头节点,那么我们就能挨个得到整个链表的所有节点。
链表的特点:
没有容量限制
没有扩容的需求
操作两头快,中间慢
线程不安全
链表的操作:
1.插入新节点:将插入位置的节点的上一个节点的Next指针赋值给新插入的节点的Next指针,再将上一个节点的Next指针指向新节点。操作完成。
插入新节点示意图
2.删除节点:将要删除的节点位置的上一个节点的Next指针赋值为要删除节点的Next节点指针即可。
删除节点示意图
由上面的示意图可知,如果是操作链表的头部和尾部,那么操作速度是最快的,如果是在对链表的中间位置进行操作,将对链表进行遍历操作。
说了一堆废话,下面开始用代码说话
链表的代码实现:
package dataStructure;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
/**
-
Created by Viking on 2019/4/7
-
实现的单向链表的集合
-
只能从前往后单向遍历
-
可插入重复元素
-
实现迭代器遍历集合
*/
public class MySingleLinkList{ private transient int modCount = 0;
private transient int size;
private Nodefirst;
private Nodelast; public void addLast(E e){
linkLast(e);
}
public E removeLast(){
if (size==0) throw new NoSuchElementException();
return unlinkLast(last);
}
public E remove(int index){
return unlink(index);
}
public E getFirst(){
return first.item;
}
public E getLast(){
return last.item;
}
public E get(int index){
checkElementIndex(index);
return node(index).item;
}/**
- 向最后一个元素添加链接.
/
private void linkLast(E e) {
final Nodel = last; *
final NodenewNode = new Node<>(e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
/ - 取消指向最后一个元素的链接.
*/
private E unlinkLast(Nodel) {
if (firstlast&&first!=null) {
first = null;
last = null;
}else if (first!=null) {
Nodenode = first; l&&i==size-1) {
int i = 1;
while (node.next!=null){
if (node.next
node.next = null;
last = node;
}else node = node.next;
i++;
}
}
size--;
modCount++;
return l.item;
}
/**
- 取消指定索引的节点
/
private E unlink(int index){
checkElementIndex(index);
Nodecursor; *
if (index0 && indexsize-1){
cursor = first;
first = null;
last = null;
}else if (index==0) {
cursor =first;
first = cursor.next;
}else if (0 < index && index < size-1){
Nodenode = first;
for (int i =0;i<index-1;i++) node = node.next;
cursor = node.next;
node.next = cursor.next;
}else {
cursor = last;
last = node(index-1);
last.next = null;
}
size--;
modCount++;
return cursor.item;
}
/ - 判断指定索引是否存在元素.
/
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/* - 返回指定索引的元素.
/
private Nodenode(int index){ *
Nodenode = first;
for (int i =0;i<index;i++) node = node.next;
return node;
}
/ - Constructs an IndexOutOfBoundsException detail message.
- Of the many possible refactorings of the error handling code,
- this "outlining" performs best with both server and client VMs.
*/
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
public int size(){
return size;
}
public boolean isEmpty(){
return size0;
}
public String toString(){
StringBuilder str = new StringBuilder();
if (firstnull){
str.append("[]");
}else {
Nodenext = first;
str.append("[");
str.append(first.item);
while (next.next!=null){
next = next.next;
str.append(",");
str.append(next.item);
}
str.append("]");
}
return str.toString();
}
/**
-
链表的节点
*/
private static class Node{
E item;
Nodenext; Node(E element, Node
next) {
this.item = element;
this.next = next;
}
}
public Iterator
myIterator(){
return new MyIterator(0);
}
public IteratormyIterator(int index){
return new MyIterator(index);
}/**
-
实现迭代器遍历容器
*/
private class MyIterator implements Iterator{
private NodelastReturned;
private Nodenext;
private int nextIndex;
private int expectedModCount = modCount;
private MyIterator(int index){
next = index == size ? null : node(index);
nextIndex = index;}
@Override
public boolean hasNext() {
return nextIndex < size;
}@Override
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();lastReturned = next; next = next.next; nextIndex++; return lastReturned.item;
}
@Override
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();Node<E> lastNext = lastReturned.next; unlink(nextIndex-1); if (next == lastReturned) next = lastNext; else nextIndex--; lastReturned = null; expectedModCount++;
}
@Override
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item);
lastReturned = next;
next = next.next;
nextIndex++;
}
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
}
实现方式我是参考了LinkedList的源码,LinkedList是双向链表实现的。
- 向最后一个元素添加链接.
编写一个测试类:
import dataStructure.MySingleLinkList;
import java.util.*;
/**
-
Created by Viking on 2019/4/7
*/
public class TestSList {
public static void main(String[] args) {
MySingleLinkListsList = new MySingleLinkList<>();
System.out.println(sList.size());
System.out.println(sList);
sList.addLast("Hello!");
sList.addLast("My");
sList.addLast("Link");
sList.addLast("List");
sList.addLast("last");
sList.addLast("same");
sList.addLast("same");
System.out.println(sList.size());
System.out.println(sList.isEmpty());
System.out.println(sList);
System.out.println("index of 0:"+sList.get(0));
System.out.println("index of 1:"+sList.get(1));
System.out.println("index of 2:"+sList.get(2));
System.out.println("index of 3:"+sList.get(3));
System.out.println("index of 4:"+sList.get(4));
System.out.println("getFirst:"+sList.getFirst());
System.out.println("getLast:"+sList.getLast());
System.out.println(sList);
System.out.println(sList.removeLast());
System.out.println("After remove 1 element:size="+sList.size());
System.out.println(sList.removeLast());
System.out.println("After remove 2 element:size="+sList.size());
System.out.println(sList.removeLast());
System.out.println("After remove 3 element:size="+sList.size());
System.out.println(sList.removeLast());
System.out.println("After remove 4 element:size="+sList.size());
System.out.println(sList.removeLast());
System.out.println("After remove 5 element:size="+sList.size());
System.out.println(sList);
sList.addLast("iterator");
sList.addLast("is");
sList.addLast("cool");
IteratorstringIterator = sList.myIterator();
// while (stringIterator.hasNext()){
// System.out.println(stringIterator.next());
// }
// System.out.println(sList);int i =0; while (stringIterator.hasNext()){//一迭代器对象只能执行一次迭代 System.out.println(stringIterator.next()); if (i<3) stringIterator.remove(); i++;
// if (sList.size()==1) break;
}
System.out.println(sList);
}
}
测试结果:
0
[]
7
false
[Hello!,My,Link,List,last,same,same]
index of 0:Hello!
index of 1:My
index of 2:Link
index of 3:List
index of 4:last
getFirst:Hello!
getLast:same
[Hello!,My,Link,List,last,same,same]
same
After remove 1 element:size=6
same
After remove 2 element:size=5
last
After remove 3 element:size=4
List
After remove 4 element:size=3
Link
After remove 5 element:size=2
[Hello!,My]
Hello!
My
iterator
is
cool
[is,cool]
————————————————
版权声明:本文为CSDN博主「·Diablo」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Mr__Viking/article/details/89450613