一、什么是链表
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
二、链表的存储结构
链表是线性表的一种,是一种物理存储单元上非连续的存储结构,链表中的数据元素之间是通过指针链接实现的。
链表由一系列节点组成,节点可以在运行时动态的生成。
链表中的每个节点分为两部分:一部分是存储数据的数据域,另一部分是存储下一个节点的地址的指针域。
package linkeList;
/**
* 链表的增删改查都是O(n)
* @author 32456
*
* @param <E>
*/
public class LinkedList<E> {
public class Node{
public E e;
public Node next;
public Node(E e,Node next) {
this.e = e;
this.next = next;
}
public Node(E e) {
this(e,null);
}
public Node() {
this(null,null);
}
@Override
public String toString() {
return e.toString();
}
}
private Node dummyHead;
int size;
public LinkedList() {
dummyHead = new Node(null,null);
size = 0;
}
/**
* 获取链表中的元素个数
*
*/
public int getSize() {
return size;
}
/**
* 返回链表是否为空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 在链表头添加元素e 时间复杂度为O(1)
*/
public void addFirst(E e) {
add(0,e);
}
/**
*在链表中间添加一个元素 时间复杂度为O(n)
*/
public void add(int index,E e) {
if(index < 0 || index > size) {
throw new IllegalArgumentException("Add failed Illegal index");
}
Node prev = dummyHead;
for(int i = 0;i < index;i++) {
prev = prev.next;
}
Node node = new Node(e);
node.next = prev.next;
prev.next = node;
size++;
}
/**
* 在链表末尾添加元素 时间复杂度为O(n)
*/
public void addLast(E e) {
add(size,e);
}
/**
* 查找链表中的某一个元素
*/
public E get(int index) {
if(index < 0 || index > size) {
throw new IllegalArgumentException("Get failed Illegal index");
}
Node cur = dummyHead.next;
for(int i = 0;i < index;i++) {
cur = cur.next;
}
return cur.e;
}
/**
* 获取链表的第一个元素
*/
public E getFirst() {
return get(0);
}
/**
* 获取链表的最后一个元素
*/
public E getLast() {
return get(size -1);
}
/**
* 修改链表中第index位置元素的值
*/
public void set(int index,E e) {
if(index < 0 || index > size) {
throw new IllegalArgumentException("Get failed Illegal index");
}
Node cur = dummyHead.next;
for(int i = 0;i < index;i++) {
cur = cur.next;
}
cur.e = e;
}
/**
* 查找链表中是否有元素e
*/
public boolean contains(E e) {
Node cur = dummyHead.next;
while(cur != null) {
if(cur.e.equals(e)) {
return true;
}
}
return false;
}
/**
* 删除链表index位置的元素,返回删除的元素 时间复杂度为O(n)
*/
public E remove(int index) {
if(index < 0 || index > size) {
throw new IllegalArgumentException("Get failed Illegal index");
}
Node prev = dummyHead.next;
for(int i = 0;i < index;i++) {
prev = prev.next;
}
Node resNode = prev.next;
prev.next = resNode.next;
resNode.next = null;
size--;
return resNode.e;
}
/**
* 删除第一个元素 时间复杂度为O(1)
*/
public E removeFirst() {
return remove(0);
}
/**
* 删除最后一个元素 时间复杂度为O(n)
*/
public E removeLast() {
return remove(size -1);
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
Node cur = dummyHead.next;
while(cur != null) {
res.append(cur+"->");
cur = cur.next;
}
res.append("NULL");
return res.toString();
}
}
四、链表实现栈
package linkeList;
public interface Stack<E> {
public int getSize() ;
public boolean isEmpty();
public void push(E e);
public E pop() ;
public E peek();
public String toString();
}
package linkeList;
public class LinkedListStack<E> implements Stack<E> {
private LinkedList<E> list;
public LinkedListStack() {
list = new LinkedList<>();
}
public int getSize() {
return list.getSize();
}
public boolean isEmpty() {
return list.isEmpty();
}
public void push(E e) {
list.addFirst(e);
}
public E pop() {
return list.removeFirst();
}
public E peek() {
return list.getFirst();
}
public String toString() {
StringBuilder res = new StringBuilder();
res.append("Stack top");
res.append(list);
return res.toString();
}
}
五、用链表实现一个队列
package linkeList;
public interface Queue<E> {
int getSize();
boolean isEmpty();
void enqueue(E e);
E dequeue();
E getFront();
}
package linkeList;
import linkeList.LinkedList.Node;
public class LinkedListQueue<E> implements Queue<E> {
private class Node{
public E e;
public Node next;
public Node(E e,Node next) {
this.e = e;
this.next = next;
}
public Node(E e) {
this(e,null);
}
public Node() {
this(null,null);
}
@Override
public String toString() {
return e.toString();
}
}
private Node head,tail;
private int size;
public LinkedListQueue() {
head = null;
tail = null;
size = 0;
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public void enqueue(E e) {
if(tail == null) {
tail = new Node(e);
head = tail;
}else {
tail.next = new Node(e);
tail = tail.next;
}
size++;
}
@Override
public E dequeue() {
if(isEmpty()) {
throw new IllegalArgumentException("Cannot dequeue from empty");
}
Node resNode = head;
head =head.next;
resNode.next = null;
if(head == null) {
tail = null;
}
size--;
return resNode.e;
}
@Override
public E getFront() {
if(isEmpty()) {
throw new IllegalArgumentException("Cannot dequeue from empty");
}
return head.e;
}
public String toString() {
StringBuilder res = new StringBuilder();
Node cur = head;
while(cur != null) {
res.append(cur+"->");
cur = cur.next;
}
res.append("NULL");
return res.toString();
}
}