学习目标:
链表的只是学习内容:
1、 创建结点 2、 添加结点 3、 删除结点 4、 其他操作 5、 使用链表实现队列学习时间:
2021年7月10日学习产出:
1、 技术笔记 1 遍 2、CSDN 技术博客 1 篇 3、 练习题若干前面学习的线性数据结构:1.动态数组 2.栈 3.队列
底层都是依托静态数组:靠resize解决固定容量的问题
今天学习的链表是真正的动态数据结构
链表
数据存储在结点(Node)中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f5UukT16-1629082253479)(E:\Users\asus\AppData\Roaming\Typora\typora-user-images\1629079867322.png)]
优点:不需要处理固定容量的问题,真正的动态
缺点:丧失了随机访问的能力
创建Node
// 结点的数据结构
private class Node {
private T val; // 数据内容
private Node next; // 指向下个结点的引用
Node(T val) {
this.val = val;
this.next = null;
}
@Override
public String toString() {
return val.toString();
}
}
// 构建链表
private Node head; // 头结点
private int size; // 链表中结点的个数
public MyLink() {
head = null;
}
添加结点
关键点:找到要添加结点的前一个结点
// 在任意位置插入,增加虚拟头结点
public void add(T val, int index) {
if (index > this.size || index < 0) {
throw new IllegalArgumentException("index是错误的!");
}
//使用虚拟头结点
Node dummyHead = new Node(null);
//要插入的结点
Node node = new Node(val);
dummyHead.next = head;
//找到要添加结点的前一个结点
Node preNode = dummyHead;
for (int i = 0; i < index; i++) {
preNode = preNode.next;
}
node.next = preNode.next;
preNode.next = node;
// 更新size
this.size++;
// 更新head
head = dummyHead.next;
}
// 在尾部添加结点
public void addLast(T val) {
add(val, this.size);
}
// 在头添加结点
public void addFirst(T val) {
add(val, 0);
}
删除结点
//根据索引删除
public T remove(int index) {
if (index >= this.size || index < 0) {
throw new IllegalArgumentException("index是错误的!");
}
Node dummyHead = new Node(null);
dummyHead.next = head;
Node preNode = dummyHead;
for (int i = 0; i < index; i++) {
preNode = preNode.next;
}
Node delNode = preNode.next;
T result = delNode.val;
preNode.next = delNode.next;
delNode.next = null;
this.size--;
head = dummyHead.next;
return result;
}
// 删除头结点
public T removeFirst() {
return remove(0);
}
// 删除尾结点
public T removeLast() {
return remove(this.size - 1);
}
// 根据内容删除
public Node remove(T val) {
Node dummyHead = new Node(null);
dummyHead.next = head;
Node preNode = dummyHead;
while (preNode.next != null) {
T result = preNode.next.val;
if (result.equals(val)) {
//删除
Node delNode = preNode.next;
preNode.next = delNode.next;
delNode.next = null;
this.size--;
} else {
preNode = preNode.next;
}
}
return dummyHead.next;
}
其他操作
public MyLink() {
head = null;
}
// 判断链表是否为空
public boolean isEmpty() {
return this.size == 0;
}
// 获取链表中结点的个数
public int getSize() {
return this.size;
}
// 获取指定索引的结点信息
public T get(int index) {
if (index > this.size || index < 0) {
throw new IllegalArgumentException("index是错误的!");
}
Node curNode = head;
for (int i = 0; i < index; i++) {
curNode = curNode.next;
}
return curNode.val;
}
// 获取头结点
public T getFirst() {
return get(0);
}
// 获取尾结点
public T getLast() {
return get(this.size - 1);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
Node cur = head;
while (cur != null) {
sb.append(cur + "-->");
cur = cur.next;
}
return sb.toString();
}
// 判断链表中是否包含指定的元素
public boolean contains(T val) {
Node curNode = head;
while (curNode != null && !curNode.val.equals(val)) {
curNode = curNode.next;
}
return curNode != null;
}
// 根据索引更新链表中的结点内容
public void set(int index, T val) {
if (index >= this.size || index < 0) {
throw new IllegalArgumentException("index是错误的!");
}
Node curNode = head;
for (int i = 0; i < index; i++) {
curNode = curNode.next;
}
curNode.val = val;
}
测试
public static void main(String[] args) {
int count = 10;
Random random = new Random();
MyLink<Integer> myLink = new MyLink<>();
for (int i = 0; i < count; i++) {
myLink.addFirst(random.nextInt(100));
}
System.out.println(myLink);
System.out.println("在尾部的位置插入");
myLink.addLast(random.nextInt(100));
System.out.println(myLink);
System.out.println("在头部的位置插入");
myLink.addFirst(random.nextInt(100));
System.out.println(myLink);
System.out.println("获取头部结点" + myLink.getFirst());
System.out.println("获取尾部结点" + myLink.getLast());
System.out.println("获取索引为3的结点" + myLink.get(3));
System.out.println("总共有多少个结点" + myLink.getSize());
System.out.println("判断15是否存在?" + myLink.contains(15));
System.out.println("更新索引为10的元素为99");
myLink.set(10, 99);
System.out.println(myLink);
System.out.println("删除head");
myLink.removeFirst();
System.out.println(myLink);
System.out.println("删除tail");
myLink.removeLast();
System.out.println(myLink);
System.out.println("删除索引为2");
myLink.remove(2);
System.out.println(myLink);
}
使用链表实现队列
public class LinkedQueue<T> implements Queue<T> {
private MyLink<T> data;
public LinkedQueue() {
data = new MyLink<>();
}
@Override
public int getSize() {
return data.getSize();
}
@Override
public boolean isEmpty() {
return data.isEmpty();
}
@Override
public void enqueue(T ele) {
data.addLast(ele);
}
@Override
public T dequeue() {
return data.removeFirst();
}
@Override
public T getFront() {
return data.getFirst();
}
}