目录
单向链表(Single Linked List)
双端链表(HeadTailLinkedList)
双向链表(DoubleLinkedList)
总结
链表(Linked List)是一种物理存储单元上非连续、非顺序的存储结构,它既可以表示线性结构,也可以用于表示非线性结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
链表由一系列结点组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
Node类:
package yrwan06;
public class Node {
public int data;// 数据域
public Node next;// 指针域:指向下一个结点
public Node prev;// 指针域:指向前一个结点
public Node(int data) {
this.data = data;
}
public void display(){
System.out.print(data + " ");
}
}
单向链表(Single Linked List)
单向链表是链表中结构最简单的。一个单向链表的结点(Node)分为两个部分,第一个部分保存结点的数据,另一个部分存储下一个结点的地址。
单向链表只可沿一个方向遍历,一般查找一个结点的时要从第一个结点开始顺次遍历,直至访问到所需位置。插入一个结点,在这里只提供在表头插入,只需将当待插入结点设为头结点,将其next指向原头结点即可。删除一个结点时,将该结点的上一个结点的next指向该结点的下一个结点即可。
实现代码:
package yrwan06;
/**
* 单向链表,只能在表头插入
*
* @author Wyran
*
*/
public class SingleLinkedList {
private int size;
private Node head;
public SingleLinkedList() {
size = 0;
head = null;
}
/**
* 在表头添加元素
*
* @param value 待插入元素
*/
public void insertHead(int value) {
Node newHead = new Node(value);
if (size == 0) {
head = newHead;
} else {
newHead.next = head;
head = newHead;
}
size++;
}
/**
* 删除表头
*
* @return 所删除的结点
*/
public Node deleteHead() {
Node temp = head;
if (size == 1) {
head = null;
} else {
head = head.next;
}
size--;
return temp;
}
/**
* 根据传入的值删除结点
*
* @param value 待删除的值
* @return 所删除的结点
*/
public Node delete(int value) {
Node current = head;
Node previous = head;
while (current.data != value) {
if (current.next == null) {
return null;
} else {
previous = current;
current = current.next;
}
}
// 如果删除的结点是第一个结点
if (current == head) {
head = head.next;
} else {// 删除的结点不是第一个结点
previous.next = current.next;
}
size--;
return current;
}
/**
* 查找指定元素
*
* @param value 待查找元素
* @return 找到了返回该结点,找不到返回null
*/
public Node find(int value) {
Node current = head;
while (current.data != value) {
if (current.next == null) {
return null;
}
current = current.next;
}
return current;
}
// 判断链表是否为空
public boolean isEmpty() {
return (size == 0);
}
// 遍历显示
public void display() {
Node temp = head;
while (temp != null) {
temp.display();
temp = temp.next;
}
}
}
测试类为:
package yrwan06;
public class SingleLinkedListTest {
public static void main(String[] args) {
SingleLinkedList sll = new SingleLinkedList();
sll.insertHead(1);
sll.insertHead(2);
sll.insertHead(3);
sll.insertHead(4);
sll.insertHead(5);
sll.insertHead(6);
sll.display();
System.out.println("-------------");
sll.deleteHead();
sll.display();
System.out.println("-------------");
sll.find(3).display();
System.out.println("-------------");
sll.delete(5).display();
System.out.println("-------------");
sll.display();
}
}
结果为:
6 5 4 3 2 1 -------------
5 4 3 2 1 -------------
3 -------------
5 -------------
4 3 2 1
双端链表(HeadTailLinkedList)
在单链表的基础上,增加对尾结点的引用,可以很方便的在链表尾部增加数据
实现代码:
package yrwan06;
/**
* 双端链表,可在表头、表尾插入
*
* @author Wyran
*
*/
public class HeadTailLinkedList {
private int size;
private Node head;
private Node tail;
public HeadTailLinkedList() {
size = 0;
head = null;
tail = null;
}
/**
* 在表头添加元素
*
* @param value 待插入元素
*/
public void insertHead(int value) {
Node newHead = new Node(value);
if (size == 0) {// 如果链表为空,那么头、尾结点都是该新增结点
head = newHead;
tail = newHead;
} else {
newHead.next = head;
head = newHead;
}
size++;
}
/**
* 在表尾添加元素
*
* @param value 待插入元素
*/
public void insertTail(int value) {
Node newTail = new Node(value);
if (size == 0) {// 如果链表为空,那么头、尾结点都是该新增结点
head = newTail;
tail = newTail;
} else {
tail.next = newTail;
tail = newTail;
}
size++;
}
/**
* 删除表头
*
* @return 所删除的结点
*/
public Node deleteHead() {
Node temp = head;
if (size == 1) {
head = null;
tail = null;
} else {
head = head.next;
}
size--;
return temp;
}
/**
* 根据传入的值删除结点
*
* @param value 待删除的值
* @return 所删除的结点
*/
public Node delete(int value) {
Node current = head;
Node previous = head;
while (current.data != value) {
if (current.next == null) {
return null;
} else {
previous = current;
current = current.next;
}
}
// 如果删除的结点是第一个结点
if (current == head) {
head = head.next;
} else {// 删除的结点不是第一个结点
previous.next = current.next;
}
size--;
return current;
}
/**
* 查找指定元素
*
* @param value 待查找元素
* @return 找到了返回该结点,找不到返回null
*/
public Node find(int value) {
Node current = head;
while (current.data != value) {
if (current.next == null) {
return null;
}
current = current.next;
}
return current;
}
// 判断链表是否为空
public boolean isEmpty() {
return (size == 0);
}
// 遍历显示
public void display() {
Node temp = head;
while (temp != null) {
temp.display();
temp = temp.next;
}
}
}
测试类:
package yrwan06;
public class HeadTailLinkedListTest {
public static void main(String[] args) {
HeadTailLinkedList htll = new HeadTailLinkedList();
htll.insertHead(1);
htll.insertHead(2);
htll.insertHead(3);
htll.insertTail(4);
htll.insertTail(5);
htll.insertTail(6);
htll.display();
System.out.println("-------------");
htll.deleteHead();
htll.display();
System.out.println("-------------");
htll.find(4).display();
System.out.println("-------------");
htll.delete(5).display();
System.out.println("-------------");
htll.display();
}
}
结果为:
3 2 1 4 5 6 -------------
2 1 4 5 6 -------------
4 -------------
5 -------------
2 1 4 6
双向链表(DoubleLinkedList)
构造一个链表,其每个结点除了保存对下一个结点的引用,还保存了对上一个结点的引用,使之在头部尾部都可以增删数据,并且可以从两个方向遍历。
实现代码:
package yrwan06;
/**
* 双向链表,可在表头、表尾插入删除,可从两个方向遍历
*
* @author Wyran
*
*/
public class DoubleLinkedList {
private int size;
private Node head;
private Node tail;
public DoubleLinkedList() {
size = 0;
head = null;
tail = null;
}
/**
* 在表头添加元素
*
* @param value 待插入元素
*/
public void insertHead(int value) {
Node newHead = new Node(value);
if (size == 0) {// 如果链表为空,那么头、尾结点都是该新增结点
head = newHead;
tail = newHead;
} else {
head.prev = newHead;
newHead.next = head;
head = newHead;
}
size++;
}
/**
* 在表尾添加元素
*
* @param value 待插入元素
*/
public void insertTail(int value) {
Node newTail = new Node(value);
if (size == 0) {// 如果链表为空,那么头、尾结点都是该新增结点
head = newTail;
tail = newTail;
} else {
tail.next = newTail;
newTail.prev = tail;
tail = newTail;
}
size++;
}
/**
* 删除表头
*
* @return 所删除的结点
*/
public Node deleteHead() {
Node temp = head;
if (size == 1) {
head = null;
tail = null;
} else {
head = head.next;
head.prev = null;
}
size--;
return temp;
}
/**
* 删除表尾
*
* @return 所删除的结点
*/
public Node deleteTail() {
Node temp = tail;
if (size == 1) {
head = null;
tail = null;
} else {
tail = tail.prev;
tail.next = null;
}
size--;
return temp;
}
/**
* 根据传入的值删除结点
*
* @param value 待删除的值
* @return 所删除的结点
*/
public Node delete(int value) {
Node current = head;
while (current.data != value) {
if (current.next == null) {
return null;
} else {
current = current.next;
}
}
// 如果删除的结点是第一个结点
if (current == head) {
head = head.next;
head.prev = null;
} else {// 删除的结点不是第一个结点
current.prev.next = current.next;
current.next.prev = current.prev;
}
size--;
return current;
}
/**
* 查找指定元素
*
* @param value 待查找元素
* @return 找到了返回该结点,找不到返回null
*/
public Node find(int value) {
Node current = head;
while (current.data != value) {
if (current.next == null) {
return null;
}
current = current.next;
}
return current;
}
// 判断链表是否为空
public boolean isEmpty() {
return (size == 0);
}
// 遍历显示
public void display() {
Node temp = head;
while (temp != null) {
temp.display();
temp = temp.next;
}
}
}
测试类:
package yrwan06;
public class DoubleLinkedListTest {
public static void main(String[] args) {
DoubleLinkedList dld = new DoubleLinkedList();
dld.insertHead(1);
dld.insertHead(2);
dld.insertHead(3);
dld.insertTail(4);
dld.insertTail(5);
dld.insertTail(6);
dld.display();
System.out.println("-------------");
while (!dld.isEmpty()) {
dld.deleteHead();
dld.display();
System.out.println();
}
// while (!dld.isEmpty()) {
// dld.deleteTail();
// dld.display();
// System.out.println();
// }
}
}
结果为:
3 2 1 4 5 6 -------------
2 1 4 5 6
1 4 5 6
4 5 6
5 6
6
总结
每个链表都一个LinikedList对象和许多Node对象组成,LinkedList对象通常包含头和尾结点的引用,分别指向链表的第一个结点和最后一个结点。而每个结点对象通常包含数据部分data,以及对上一个结点的引用prev和下一个结点的引用next,只有下一个结点的引用称为单向链表,两个都有的称为双向链表。
next值为null则说明是链表的结尾,如果想找到某个结点,必须从第一个结点开始遍历,不断通过next找到下一个结点,直到找到所需要的。
栈和队列都是ADT,可以用数组来实现,也可以用链表实现。