文章目录
前言
单链表是一种链式存取的数据结构,链表中的数据是以结点来表示的,每个结点由元素和指针构成。
元素表示数据元素的映象,就是存储数据的存储单元;指针指示出后继元素存储位置,就是连接每个结点的地址数据。
以结点的序列
表示的线性表称作线性链表,也就是单链表,单链表是链式存取的结构。
链表:真正的动态数据结构
一、链表
数据存储在"结点"(Node)中
优点:不需要处理固定容积问题,真正的动态
缺点:丧失了随机访问的能力
二、创建Node
public class LinkedList<T extends Comparable<T>> {
//链表的相关属性
private Node head;//链表的头
private int size;//链表中结点的个数
//创建Node 内部类
private class Node {
//结点中的内容
T ele;
//索引,指向下一个结点
Node next;
public Node(T ele) {
this.ele = ele;
}
@Override
public String toString() {
return ele.toString();
}
}
public LinkedList() {
this.head = null;
this.size = 0;
}
}
三、对链表进行增加操作
//原始方法
public void addHead(T ele) {
//1.先创建结点
Node node = new Node(ele);
//2.node.next -> head
node.next = head;
//3.更新head到node
head = node;
//4.更新size
this.size++;
}
//在头部添加结点
public void addHead(T ele) {
add(0,ele);
}
//在链表的尾部添加
public void addTail(T ele){
add(this.size,ele);
}
//在任意位置添加: 关键点:找到待添加位置的前一个结点
public void add(int index,T ele) {
if(index < 0 || index > this.size) {
throw new IllegalArgumentException("index is invalid");
}
//1.创建结点
Node node = new Node(ele);
if(head == null) {
head = node;
this.size++;
return;
}
//在索引为0的位置添加,因为头结点没有前置结点
if(index == 0) {
node.next = head;
head = node;
this.size++;
return;
}
//2.找到待添加位置的前一个结点
Node pre = head;
for (int i = 0; i < index; i++) {
pre = pre.next;
}
//3.进行操作
node.next = pre.next;
pre.next = node;
this.size++;
}
四、使用虚拟头结点
//在任意位置添加: 关键点:找到待添加位置的前一个结点
public void add(int index,T ele) {
if(index < 0 || index > this.size) {
throw new IllegalArgumentException("index is invalid");
}
//(0) 创建虚拟头结点 dummyHead
Node dummyHead = new Node(null);
dummyHead.next = head;
//1.创建结点
Node node = new Node(ele);
//2.找到待添加位置的前一个结点
Node pre = dummyHead;
for (int i = 0; i < index; i++) {
pre = pre.next;
}
//3.进行操作
node.next = pre.next;
pre.next = node;
head = dummyHead.next;
this.size++;
}
五、链表的遍历、查询、更新操作
//遍历链表
public String showLinkedList() {
//定义当前结点
Node cur = head;
StringBuilder sb = new StringBuilder();
while(cur!=null) {
sb.append(cur+"-->");
//更新当前结点的值
cur = cur.next;
}
return sb.toString();
}
//获取链表头的元素
public T getHead() {
return this.head == null ? null : this.head.ele;
}
//获取链表的最后一个元素
public T getTail() {
if (head == null) {
return null;
}
Node cur = head;
for (int i = 1; i < this.size; i++) {
cur = cur.next;
}
return cur.ele;
}
//根据索引获取指定位置的内容
public T get(int index) {
if(index < 0 || index >= this.size){
throw new IllegalArgumentException("index is invalid!");
}
if(head == null){
return null;
}
Node cur = head;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
return cur.ele;
}
//获取链表中结点的个数
public int getSize() {
return this.size;
}
//判断链表是否为空
public boolean isEmpty() {
return this.size == 0;
}
//判断指定的内容是否存在
public boolean contains(T ele) {
Node cur = head;
while (cur != null) {
if (cur.ele.compareTo(ele) == 0) {
return true;
}
cur = cur.next;
}
return false;
}
//更新指定位置结点的内容
public void set(int index,T ele){
if(index < 0 || index >= this.size){
throw new IllegalArgumentException("index is invalid!");
}
Node cur = head;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
cur.ele = ele;
}
六、从链表中删除元素
删除任意位置的结点:
//删除任意位置的结点
public T remove(int index) {
if(index < 0 || index >= this.size) {
throw new IllegalArgumentException("index is invalid!");
}
Node dummyHead = new Node(null);
dummyHead.next = head;
//找到删除结点的前置结点
Node pre = dummyHead;
for (int i = 0; i < index; i++) {
pre = pre.next;
}
//1.获取删除结点
Node removeNode = pre.next;
T result = removeNode.ele;
this.size--;
//2.删除
pre.next = removeNode.next;
removeNode.next = null;
//3.重置头结点
head = dummyHead.next;
return result;
}
//删除链表头结点
public T removeHead(){
/*if(head == null){
return null;
}
T result = head.ele;
head = head.next;
this.size--;
return result;*/
return remove(0);
}
//根据内容来删除链表中的结点
public void remove(T val){
head = remove(head,val);
}
//从以node为头结点的链表中删除值为val的头结点
private Node remove(Node node,T val){
//1、递归终止的条件
if(node == null){
return null;
}
//2、递归操作
if(node.ele.compareTo(val) == 0){
return node.next;
}else{
node.next = remove(node.next,val);
return node;
}
}
//删除链表尾节点
public T removeTail() {
return remove(this.size-1);
/*if(head == null) {
return null;
}
Node pre = head;
for (int i = 1; i < this.size-1; i++) {
pre = pre.next;
}
Node node = pre.next;
T result = node.ele;
pre.next = node.next;
node.next = null;
this.size--;
return result;*/
}
七、链表的时间复杂度分析
添加操作:
addList(e) O(n)
addFirst(e) O(1)
add(index,e) O(n/2)= O(n)
删除操作:
removeLst(e) O(n)
removeFirst(e) O(1)
remove(index) O(n/2)=O(n)
修改操作 O(n)
set(index,e) O(n)
查找操作:
get(index) O(n)
contains(e) O(n)
find(e) O(n)