一.链表
典型的链表结构,链表中每个结点都应该包括如下内容:
- 数据部分,保存的是该结点的实际数据;
- 地址部分,保存的是下一个结点的地址。
由于采用了引用来指示下一个数据的地址。因此在链表结构中,逻辑上相邻的结点在内存中不一定相邻,逻辑相邻关系通过地址部分的引用变量来实现。
(1)链表优点:
链表最大的好处是结点之间不要求连续存放,因此在保存大量数据的同时,不需要分配一块连续的存储空间。
用户可以用new函数动态分配结点的存储空间,当删除某个结点时,给该结点赋值null,释放其占用的内存空间。
(2)链表缺点:
浪费存储空间。对于每个结点数据,都要额外保存一个引用变量。
(3)链表访问方式:
从表头逐个查找,即通过head头引用找到第一个结点,再从第一个结点找到第二个结点....这样逐个比较一直找到需要的结点为止。而不能像顺序表一样随机访问。
二.单链表
1.单链表定义
单向链表(又名单链表、线性链表)是链表的一种,其特点是链表的链接方向是单向的(每个结点中只包含一个引用),对链表的访问要通过从头部开始,依序往下读取。
2.单链表的操作
单链表的主要操作有以下几个:
(1)在链表结尾追加结点;
(2)获取下一个结点;
(3)获取最后一个结点;
(4)判断当前结点是否为最后结点;
(5)删除下一个结点;
(6)展示链表的所有结点;
(7)插入一个结点作为当前结点的下一个结点。
package cn.kimtian.linkedlist;
/**
* 这是链表的一个结点
*
* @author kimtian
*/
public class Node {
/**
* 结点内容(存任何类型都可以)
*/
private int data;
/**
* 下一个结点
*/
Node next;
/**
* 创建结点的时候,给一个value
*
* @param data
*/
public Node(int data) {
this.data = data;
}
/**
* 为结点追加结点(在链表的结尾)
*
* @param node
*/
public Node appendNode(Node node) {
//开始是当前结点
Node currentNode = this;
//循环向后找
while (true) {
//取出下一个节点,赋值给当前结点
Node nextNode = currentNode.next;
//结束标记,如果下一个结点为null,当前结点已经是最后一个结点了
if (nextNode == null) {
break;
}
currentNode = nextNode;
}
//把需要追加的结点追加到找到的当前结点的下一个结点
currentNode.next = node;
//将自身返回出去
return this;
}
/**
* 获取结点的下一个结点
*/
public Node nodeNext() {
return this.next;
}
public int getData() {
return this.data;
}
/**
* 获取结点的最终结点
*/
public Node nodeFinal() {
//开始是当前结点
Node currentNode = this;
//循环向后找
while (true) {
//取出下一个节点,赋值给当前结点
Node nextNode = currentNode.next;
//结束标记,如果下一个结点为null,当前结点已经是最后一个结点了
if (nextNode == null) {
break;
}
currentNode = nextNode;
}
//将自身返回出去
return currentNode;
}
/**
* 判断当前结点是否为最后结点
*/
public boolean isLast() {
return this.next == null;
}
/**
* 删除下一个结点
*/
public void removeNext() {
//取出下下一个结点
Node newNext = next.next;
//把下下一个结点设置为当前结点的下一个结点
this.next = newNext;
}
/**
* 插入一个结点作为当前结点的下一个结点(在链表中间)
*
* @param node 插入的结点
*/
public void addNode(Node node) {
//取出下一个结点作为下下一个结点
Node nextNode = next;
//把新结点插入为当前结点的下一个结点
this.next = node;
//把下下一个结点设置为新结点的下一个结点
node.next = nextNode;
}
/**
* 显示所有结点信息
*/
public void showNodes() {
Node currentNode = this;
while (true) {
System.out.print(currentNode.data + " ");
//取出下一个结点
currentNode = currentNode.next;
//如果是最后一个结点
if (currentNode == null) {
break;
}
}
System.out.println();
}
}
三.循环链表
1.单向循环链表定义:
操作和单链表基本一致。(在单链表中,将终端结点的引用域null改为指向表头结点或开始结点即可构成单循环链表。)
只是它的最后一个结点指向头结点,形成一个环。因此,从循环链表中的任何一个结点出发都能找到任何其他结点。
2.单向循环链表的操作:
(1)插入结点;
(2)删除结点。
package cn.kimtian.linkedlist;
/**
* 循环链表
*
* @author kimtian
*/
public class LoopNode {
/**
* 结点内容(存任何类型都可以)
*/
private int data;
/**
* 下一个结点
*/
LoopNode next = this;
/**
* 创建结点的时候,给一个value
*
* @param data
*/
public LoopNode(int data) {
this.data = data;
}
/**
* 获取结点的下一个结点
*/
public LoopNode nodeNext() {
return this.next;
}
public int getData() {
return this.data;
}
/**
* 删除下一个结点
*/
public void removeNext() {
//取出下下一个结点
LoopNode newNext = next.next;
//把下下一个结点设置为当前结点的下一个结点
this.next = newNext;
}
/**
* 插入一个结点作为当前结点的下一个结点(在链表中间)
*
* @param node 插入的结点
*/
public void addNode(LoopNode node) {
//取出下一个结点作为下下一个结点
LoopNode nextNode = next;
//把新结点插入为当前结点的下一个结点
this.next = node;
//把下下一个结点设置为新结点的下一个结点
node.next = nextNode;
}
}
3.双向循环链表定义
若每个结点包含两个引用,一个指向下一个结点,另一个指向上一个结点,这就是双向链表。
4.双向链表操作
(1)增加一个结点;
(2)获取上一个结点;
(3)获取下一个结点;
package cn.kimtian.linkedlist;
/**
* 这是一个双向链表
*
* @author kimtian
*/
public class DoubleNode {
/**
* 结点内容(存任何类型都可以)
*/
private int data;
public int getData() {
return data;
}
/**
* 上一个结点
*/
DoubleNode preDoubleNode = this;
/**
* 下一个结点
*/
DoubleNode nextDoubleNode = this;
/**
* 创建结点的时候,给一个value
*
* @param data
*/
public DoubleNode(int data) {
this.data = data;
}
/**
* 增加一个结点
*
* @param doubleNode 结点
*/
public void addDoubleNode(DoubleNode doubleNode) {
//取出下一个结点作为下下一个结点
DoubleNode nextNode = nextDoubleNode;
//把新结点插入为当前结点的下一个结点
this.nextDoubleNode = doubleNode;
//把当前结点作为新结点的前一个结点
doubleNode.preDoubleNode = this;
//把下下一个结点设置为新结点的下一个结点
doubleNode.nextDoubleNode = nextNode;
//把下下一个结点的上一个结点设置为新结点
nextNode.preDoubleNode = doubleNode;
}
/**
* 获取下一个结点的方法
*/
public DoubleNode getNext() {
return this.nextDoubleNode;
}
/**
* 获取上一个结点的方法
*/
public DoubleNode getPre() {
return this.preDoubleNode;
}
}
5.多重链的循环链表:
如果将表中的结点链在多个环上,将构成多重链的循环链表。