33

结构与算法(03):单向链表和双向链表

 3 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzU4Njg0MzYwNw%3D%3D&%3Bmid=2247484882&%3Bidx=1&%3Bsn=224cb2bbef7cc87a35c05d0f5bc58226
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、链表简介

1、链表概念

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列节点组成,节点可以在运行时动态生成,节点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

2、基础特点

内存存储

zqIBFnj.png!mobile

逻辑结构

URniErY.png!mobile

特点描述

  • 物理存储上是无序且不连续的;

  • 链表是由多个节点以链式结构组成;

  • 逻辑层面上看形成一个有序的链路结构;

链表结构解决数组存储需要预先知道元素个数的缺陷,可以充分利用内存空间,实现灵活的内存动态管理。

二、单向链表

1、基础描述

jERRFz.png!mobile

单向链表是链表的一种,其特点是链表的链接方向是单向的,链表的遍历要从头部开始顺序读取;结点构成,head指针指向第一个成为表头结点,终止于最后一个指向NULL的指针。

2、基础操作

添加数据

i2INFb.png!mobile

  • 初始化head节点,作为链表的头;

  • 修改当前末尾节点的next指针;

  • 新添加的节点房子在链表末尾;

删除数据

ARRJ7bv.png!mobile

遍历找到要删除的节点,把删除节点前个节点的指针指向该删除节点的下个节点;

三、双向链表

1、概念描述

YniaQj.png!mobile

双向链表也叫双链表,是链表的一种,链表的每个数据结点中都有两个指针,分别指向直接后继和直接前驱,从双向链表中的任意一个结点开始,都可以很快速地访问它的前驱结点和后继结点,链表结构的使用多数都是构造双向循环链表。

2、基础操作

添加数据

NviUvqF.png!mobile

  • 遍历找到链表的最后一个节点;

  • 修改当前末尾节点的next指针;

  • 新添加的节点房子在链表末尾;

  • 添加最新尾节点的prev指针;

删除数据

Q7f6nqv.png!mobile

  • 双向链表,基于要删除节点操作即可;

  • 操作上图中要删除的Node2节点;

  • Node2.prev.next = Node2.next;

  • Node2.next.prev = Node2.prev;

通过上述流程的操作,就把链表中一个节点删除,剩下节点再度连接成链式结构。

3、源码分析

在Java的API中,LinkedList是典型的双向链表结构,下面基于LinkedList源码看双向链表的操作。

基础案例

public class M01_Linked {
public static void main(String[] args) {
List<User> userList = new LinkedList<>() ;
User removeUser = new User(200,"Second") ;
// 添加元素
userList.add(new User(100,"First")) ;
userList.add(removeUser) ;
userList.add(new User(300,"Third")) ;
System.out.println("初始化:"+userList);
// 修改元素
userList.get(0).setUserName("Zero");
System.out.println("修改后:"+userList);
// 删除元素
userList.remove(removeUser) ;
System.out.println("删除后:"+userList);
}
}
class User {
private Integer userId ;
private String userName ;
public User(Integer userId, String userName) {
this.userId = userId;
this.userName = userName;
}
@Override
public String toString()
{
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
'}';
}
// 省略Get和Set方法
}

节点描述

节点三个核心描述:数据,next指针,prev指针。

private static class Node<E> {
E item; // 数据
Node<E> next; // 下个指针
Node<E> prev; // 上个指针
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}

首位节点处理

基于LinkedList源码,首尾节点方式,针对上图双链表的首位指针特点,这里源码很好理解。

public class LinkedList {
transient Node<E> first;
transient Node<E> last;
// 处理首节点
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
}
// 处理尾节点
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
}
}

添加节点

添加节点的方法直接调用linkLast方法,把新节点放到链表的尾部即可。

public boolean add(E e) {
linkLast(e);
return true;
}

删除节点

第一步:遍历对比,找到要删除的节点;

public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}

第二步:移除节点,重新搭建链表结构,并且把当前链表的数据置为null,并返回被移除的节点;

E unlink(Node<E> x) {
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
return element;
}

如上就是对Java中LinkedList双链表源码的部分结构分析,这种代码看多了,总感觉自己写的代码不是Java。

四、环形链表

在单链表中,将终端结点的指针域NULL改为指向表头结点或开始结点,这样就形成了环形链表:

3A3meyM.png!mobile

环形链表链表的一种结构,特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。

五、源代码地址

GitHub·地址
https://github.com/cicadasmile/model-arithmetic-parent
GitEE·地址
https://gitee.com/cicadasmile/model-arithmetic-parent

uaE36bV.png!mobile


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK