链表定义
链表是一种物理存储单元上非连续,非顺序的存储结构。其物理结构不能直观的表示数据元素的逻辑顺序,数据元素的逻辑顺序是通过链表的指针连接顺序实现的。链表由一系列的结点组成,链表中的每一个元素称为结点,结点可以在运行时动态生成。
链表数据
插入数据
在结点A和结点B之间插入结点F,操作如下:
- 结点F的指针指向节点B
- 结点A的指针指向结点F
删除数据
删除结点B的操作如下
- 结点A指针指向结点C。
- 结点B指针不在指向结点C。
结点类定义
结点API
类名 | Node |
构造方法 | Node(T item, Node<T> next) |
成员变量 | T item; // 存储数据 Node<T> next; //存储指针 |
定义结点Node
@Data
public class Node<T> {
private T item;
private Node<T> next;
public Node(T item, Node<T> next) {
this.item = item;
this.next = next;
}
}
生成链表
public static void main(String[] args) {
Node<String> aNode = new Node<>("A",null);
Node<String> bNode = new Node<>("B",null);
Node<String> cNode = new Node<>("C",null);
Node<String> dNode = new Node<>("D",null);
Node<String> gNode = new Node<>("G",null);
aNode.next = bNode;
bNode.next = cNode;
cNode.next = dNode;
dNode.next = gNode;
}
单向链表
单向链表描述
单向链表是链表的一种,它有多个结点组成,每个结点都有一个数据域和一个指针域组成,数据域用来存储数据,指针域用来指向其后继结点。链表的头结点的数据域不存储数据,指针域指向第一个真正存储数据的结点。
单向链表API
类名 | LinkList |
构造方法 | LinkList() |
成员方法 | public void clear() //清空链表 public int size() //链表长度 public boolean isEmpty() //链表是否为空 public T get(int i) //获取i位置的值 |
成员内部类 | private static class Node<T> 结点类 private class LIterator implements Iterator<T> |
成员变量 | private Node<T> head; //头结点 private int size; //链表长度 |
单向链表实现
import java.util.Iterator;
/**
* 单向链表
*/
public class LinkList<T> implements Iterable<T> {
/**
* 头结点
*/
private Node<T> head;
/**
* 链表长度
*/
private int size;
/**
* 初始化链表
*/
public LinkList() {
head = new Node<T>(null, null);
size = 0;
}
/**
* 清空链表
*/
public void clear() {
this.head.next = null;
this.size = 0;
}
/**
* 链表长度
*/
public int size() {
return size;
}
/**
* 链表是否为空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 获取i位置的值
*/
public T get(int i) {
if (i < 0 || i > size) {
throw new RuntimeException("i位置错误");
}
if (isEmpty()) {
throw new RuntimeException("LinkList is empty !");
}
Node<T> node = this.head.next;
for (int index = 0; index < i; index++) {
node = node.next;
}
return node.item;
}
/**
* 插入元素
*/
public void insert(T t) {
Node<T> node = this.head;
while (node.next != null) {
node = node.next;
}
Node newNode = new Node(t, null);
newNode.next = newNode;
size++;
}
/**
* 在指定位置插入元素
*/
public void insert(int i, T t) {
if (i < 0 || i > size) {
throw new RuntimeException("i位置错误");
}
Node<T> pre = head;
for (int index = 0; index <= i - 1; index++) {
pre = pre.next;
}
Node currentNode = pre.next;
Node<T> node = new Node<>(t, currentNode);
pre.next = node;
size++;
}
/**
* 移除指定位置的元素
*/
public T remove(int i) {
if (i < 0 || i > size) {
throw new RuntimeException("i位置错误");
}
Node<T> pre = head;
for (int index = 0; i < i; index++) {
pre = pre.next;
}
Node<T> currentNode = pre.next;
pre.next = currentNode.next;
size--;
return currentNode.item;
}
/**
* 查找元素的位置
*/
public int indexOf(T t) {
Node node = head;
int i = -1;
while (node.next != null) {
node = node.next;
i++;
if (node.item.equals(t)) {
return i;
}
}
return i;
}
@Override
public Iterator<T> iterator() {
return new LIterator();
}
private class LIterator implements Iterator<T> {
private Node<T> node;
public LIterator() {
node = head;
}
@Override
public boolean hasNext() {
return node.next != null;
}
@Override
public T next() {
return node.next.item;
}
}
private static class Node<T> {
private T item;
private Node<T> next;
public Node(T item, Node<T> next) {
this.item = item;
this.next = next;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
public Node<T> getNext() {
return next;
}
public void setNext(Node<T> next) {
this.next = next;
}
}
}
双向链表
双向链表描述
双向链表也叫双向表,是链表的一种,它由多个结点组成,每个结点都有一个数据域 和 两个指针域组成,数据域用来存储数据,其中一个指针域用来指向其后继结点,另一个指针域用来指向前驱结点。链表的头结点的数据域不存储数据,指向前驱结点的指针域值为Null,指向其后继结点的指针指向第一个真正存储数据的结点。
双向链表API
类名 | TwoWayLinkList |
构造方法 | TwoWayLinkList() |
成员方法 | public void clear() //清空链表 public int size() //链表长度 public boolean isEmpty() //链表是否为空 public T get(int i) //获取i位置的值 |
成员内部类 | private static class Node<T> 结点类 private class LIterator implements Iterator<T> |
成员变量 | private Node<T> head; //头结点 private Node<T> tail; //尾结点 |
代码实现
/**
* 单向链表
*/
public class TwoWayLinkList<T> implements Iterable<T> {
/**
* 头结点
*/
private Node<T> head;
/**
* 头结点
*/
private Node<T> tail;
/**
* 链表长度
*/
private int size;
/**
* 初始化链表
*/
public TwoWayLinkList() {
head = new Node<T>(null, null, null);
tail = null;
size = 0;
}
/**
* 清空链表
*/
public void clear() {
this.head.next = null;
this.tail = null;
this.size = 0;
}
/**
* 链表长度
*/
public int size() {
return size;
}
/**
* 链表是否为空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 获取i位置的值
*/
public T get(int i) {
if (i < 0 || i >= size) {
throw new RuntimeException("i位置错误");
}
if(this.head.next == null){
return null;
}
Node<T> currrent = this.head.next;
for(int index = 0;index < i;index ++){
currrent = currrent.next;
}
return currrent.item;
}
/**
* 插入元素
*/
public void insert(T t) {
if (this.tail == null) {
tail = new Node<>(t, head, null);
head.next = tail;
} else {
Node<T> oldNode = tail;
Node<T> newNode = new Node<>(t, head, oldNode);
oldNode.next = newNode;
this.tail = newNode;
}
size++;
}
/**
* 在指定位置插入元素
*/
public void insert(int i, T t) {
if (i < 0 || i >= size) {
throw new RuntimeException("i位置错误");
}
Node<T> pre = head;
for (int index = 0; index <= i - 1; index++) {
pre = pre.next;
}
Node currentNode = pre.next;
Node<T> node = new Node<>(t,pre, currentNode);
pre.next = node;
currentNode.pre = node;
size++;
}
/**
* 移除指定位置的元素
*/
public T remove(int i) {
if (i < 0 || i >= size) {
throw new RuntimeException("i位置错误");
}
if(isEmpty()){
throw new RuntimeException("TwoWayLinkList is empty!");
}
Node<T> pre = head;
for (int index = 0; index < i; index++) {
pre = pre.next;
}
Node<T> currentNode = pre.next;
Node<T> nextNode = currentNode.next;
pre.next = nextNode;
nextNode.pre = currentNode;
size--;
return currentNode.item;
}
/**
* 查找元素的位置
*/
public int indexOf(T t) {
Node node = head;
int i = -1;
while (node.next != null) {
node = node.next;
i++;
if (node.item.equals(t)) {
return i;
}
}
return i;
}
@Override
public Iterator<T> iterator() {
return new LIterator();
}
private class LIterator implements Iterator<T> {
private Node<T> node;
public LIterator() {
node = head;
}
@Override
public boolean hasNext() {
return node.next != null;
}
@Override
public T next() {
return node.next.item;
}
}
private static class Node<T> {
private T item;
private Node<T> pre;
private Node<T> next;
public Node(T item, Node<T> pre, Node<T> next) {
this.item = item;
this.pre = pre;
this.next = next;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
public Node<T> getNext() {
return next;
}
public void setNext(Node<T> next) {
this.next = next;
}
public Node<T> getPre() {
return pre;
}
public void setPre(Node<T> pre) {
this.pre = pre;
}
}
}