分析:
- 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。
- 单链表是链表中结构最简单的。一个单链表的节点(Node)分为两个部分,一个是数据域,一个是节点域。
- 双向链表可以从两个方向遍历
1. 单向链表
1)定义一个节点
class Node<E> {
E e;
Node<E> next;
public Node(E e,Node<E> next){
this.e = e;
this.next = next;
}
public Node(E e){
this(e,null);
}
}
2)构造函数
//虚拟头节点
private Node<E> dummyHead;
private int size;
public LinkedList(){
dummyHead = new Node<>(null,null);
size = 0;
}
3)添加元素
//1->2->3->4
//1. 首先找到要插入位置的前节点
//2. 比如你要在index=2位置插入66,你就把要插入的66节点的next指向3,2的next节点指向66,然后就插入进去了
public void add(int index, E e){
Node<E> pre = dummyHead;
for (int i = 0; i < index; i++)
pre = pre.next;
Node<E> node = new Node<>(e);
//当前待插入节点的next用待插入节点的前一个节点的next指向
node.next = pre.next;
//前一个节点的next指向当前节点就对了
pre.next = node;
size++;
}
public void addFirst(E e){
add(0,e);
}
public void addLast(E e){
add(size,e);
}
3)获取数据
获取数据就是获取某一个位置的节点,然后就能获取这个节点的数据了
public E get(int index){
if(index < 0 || index > size){
throw new IllegalArgumentException("角标不合法");
}
Node<E> current = dummyHead.next;
for (int i = 0; i < index; i++) {
current = current.next;
}
return current.e;
}
public E getFirst(){
return get(0);
}
public E getLast(){
return get(size - 1);
}
4)修改数据
//首先找到要修改的index节点,然后直接修改
public void set(int index, E e){
if(index < 0 || index > size){
throw new IllegalArgumentException("角标不合法");
}
Node<E> current = dummyHead.next;
for (int i = 0; i < index; i++) {
current = current.next;
}
current.e = e;
}
5) 删除数据
//1->2->3->4
//假设我要删除2这个节点 我就应该找到它的前一个节点1,然后
//用1这个节点指向要删除节点的下一个节点,即3,删除节点的next=null
public E remove(int index){
Node<E> pre = dummyHead;
for (int i = 0; i < index; i++) {
pre = pre.next;
}
if(pre == null)
return null;
Node<E> delNode = pre.next;
pre.next = delNode.next;
delNode.next = null;
return delNode.e;
}
public E removeFirst(){
return remove(0);
}
public E removeLast(){
return remove(size - 1);
}
5)toString方法
@Override
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("LinkedList[ ");
Node<E> current = dummyHead.next;
//sb.append("NULL -> ");
while (current != null){
sb.append(current.e+" -> ");
current = current.next;
}
sb.append("NULL]");
return sb.toString();
}
2. 双向链表
1)头部插入数据
//添加一个对前一个节点的引用
public Node previous;
/**
* 插入一个结点,在头结点后进行插入
*/
public void insertFirst(long value){
Node node = new Node(value);
if(first == null){
last = node;
}else{
first.previous = node;
}
node.next = first;
first = node;
}
2)尾部插入数据
/**
* 插入一个结点,从尾结点进行插入
*/
public void insertLast(long value){
Node node = new Node(value);
if (first == null){
first = node;
}else{
last.next = node;
node.previous = last;
}
last = node;
}
3)头部删除数据
/**
* 删除一个结点,在头结点后进行删除
*/
public Node deleteFirst(){
if(first == null). return;
Node current = first;
if(first.next == null){
last = null;
}else{
first.next.previous = null;
}
first = first.next;
return current;
}
4)尾部删除数据
/**
* 删除尾节点 从尾部进行删除
*/
public Node deleteLast(){
Node current = last;
if(first.next == null){
first = null;
}else{
last.previous.next = null;
}
//后一个节点用后一个节点的前一个节点替换
last = last.previous;
return last;
}
5)删除节点数据
/**
* 根据数据删除节点
* @param value
* @return
*/
public Node delete(long value){
Node current = first;
if(current == null){
return null;
}
while (current.data != value){
current = current.next;
if(current == null){
return null;
}
}
if(current == first){
first = first.next;
}else{
//当前节点的前一个节点的下一个节点就是保留当前节点的引用
current.previous.next = current.next;
}
return current;
}
3. 用链表实现栈
基于1实现的单链表LinkedList
public class LinkedListStack<E> implements Stack<E>{
private LinkedList<E> linkedList;
public LinkedListStack(){
linkedList = new LinkedList<>();
}
//入栈
@Override
public void push(E e) {
linkedList.addFirst(e);
}
//出栈
@Override
public E pop() {
return linkedList.removeFirst();
}
//获取栈顶元素
@Override
public E peek() {
return linkedList.getFirst();
}
@Override
public boolean isEmpty() {
return linkedList.isEmpty();
}
@Override
public int size() {
return linkedList.size();
}
@Override
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("LinkedList[ ");
Node<E> current = linkedList.getNode();
while (current != null){
sb.append(current.e+" -> ");
current = current.next;
}
sb.append("NULL ]");
return sb.toString();
}
}
4. 用链表实现队列
1)构造函数
//队头 队尾
private Node<E> front;
private Node<E> tail;
private int size;
public LinkedListQueue(){
front = null;
tail = null;
size = 0;
}
2)入队
@Override
public void enqueue(E e) {
//4->3->2->1
Node<E> node = new Node<>(e);
if(tail == null){
tail = node;
front = tail;
}else{
tail.next = node;
tail = tail.next;
}
size++;
}
3)出队
@Override
public E dequeue() {
//4->3->2->1
if(isEmpty())
throw new IllegalArgumentException("队列是空的,不能出队");
Node<E> current = front;
front = front.next;
current.next = null;
if(front == null)
tail = null;
size--;
return current.e;
}
4)toString方法
@Override
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("LinkedList size "+ size +"\n");
Node<E> current = front;
sb.append("front[ ");
while (current != null){
sb.append(current.e+" -> ");
current = current.next;
}
sb.append("NULL ] tail");
return sb.toString();
}
5.联系方式
QQ:1509815887