手动实现 数组和链表
创始人
2024-05-30 15:09:32
0

数组和链表示意图

在这里插入图片描述

目的

不用java标准库
自己时间 一个 arraylist 和 linked list

区别

数组

数组 支持 随机访问 可以立即访问
根据 第一个元素的位置, 推算出 第三个地方的位置

如下图所示,假设我们知道 头的位置是X
数组是 int类型
每个位置就是 占4个字节
所以第三个元素的位置应该是 X + 3 x 4
即为 X + 12
就可以直接访问 第三个位置,直接进行赋值操作。

C语言有句话, 数组是指针, 指针不是数组。
我们 可以 把 数组就当做指针
我们知道 指针,即为 第一个元素位置
我们又可以根据 数组的类型 推断出 每个位置的大小
然后 通过 arr + X x 元素大小 直接推算出我们想修改的位置。
在这里插入图片描述

链表

链表存储的元素,它们不是连在一起放在内存的。
而是 分散位于 不同的位置。

通过 next指针记录下一个元素位置是多少,然后找到下一个元素。

只能通过 next指针 一个一个访问。
在这里插入图片描述

但是对于数组来说,每删除一个元素,需要将后面的所有元素都 往前移动1个位置。
在这里插入图片描述
对数组的增加操作,也类似,需要将后面的所有元素都 往后移动1个位置。

对于链表来说,增删都比较方便。

另外,对于数组来说,一开始就设置固定大小空间,当数组满了之后,需要重新申请一块新的空间,更大的
然后 将所有元素 都 移动过去。

数据结构的本质

遍历 和 访问

都是增删查改

postion 和 index的区别

在这里插入图片描述

数组实现

import java.util.NoSuchElementException;public class MyArrayList{// 真正存储的数据private E[] data;private int size;private static final int INIT_CAP = 1;public MyArrayList() {this(INIT_CAP);}public MyArrayList(int initCapacity) {data = (E[])new Object[initCapacity];}/** 增 **/// 在数组尾部添加一个元素 epublic void addLast(E e) {// 边界条件 Boundary conditionsif (data.length == size) {resize(data.length * 2); // 扩容 Expansion}data[size]= e;size++;}// 在index 索引位置添加一个元素 elementprivate void add(int index, E element) {checkPositionIndex(index); // 注意这里检查positionif (data.length == size) {resize(data.length * 2); // 扩容 Expansion}// data[index...] -> data[index+1 ....]// 数据迁移 Data migrationSystem.arraycopy(data, index, data, index + 1, size - 1);// 数据赋值 Data assignmentdata[index] = element;size++;}/** 删 **/// 删除数组的最后一个元素 并 返回public E removeLast() {if (isEmpty()) { // 数组为空throw new NoSuchElementException();}if (size < data.length / 4) { // 缩容 Shrinkageresize(data.length / 2);}E last = data [size - 1];// 删除最后一个元素 Delete the last elementdata[size - 1] = null;size--;return last;}// 删除index 对应的元素 并返回public E remove(int index) {checkElementIndex(index);if (size < data.length / 4) {resize (data.length / 2);}// 数据迁移// data[index + 1....] -> data[index...]E delVal = data[index];System.arraycopy(data, index + 1, data,  index,size - index - 1);// 删除最后一个元素data[size - 1] = null;size--;return delVal;}/** 查 **/// 返回索引 index 对应的元素public E get(int index) {checkElementIndex(index);return data[index];}/** 改 **/// 将索引 index的元素 修改为 element 并返回之前的值public E set(int index, E element) {checkElementIndex(index);E oldVal = data[index];data[index] = element;return oldVal;}/** 工具函数 */public int size() {return size;}public boolean isEmpty() {return size == 0;}/*** 私有函数*/// 明确index 和 postion区别private boolean isElementIndex(int index) {return index >= 0 && index < size;}private boolean isPositionIndex(int index) {return index >= 0 && index <= size;}// 检查 index 索引位置是否可以存在元素private void checkElementIndex(int index) {if (!isElementIndex(index)) {throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);}}private void checkPositionIndex(int index) {if (!isPositionIndex(index)) {throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);}}private void resize(int newCap) {E[] temp = (E[]) new Object[newCap];System.arraycopy(data, 0, temp, 0, size);data = temp;}
}

数组增加元素(add)的图解

再写一遍。逻辑同上面


import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;public class MyArrayList implements Iterable {// 真正存储数据的底层数组 The underlying array that really stores dataprivate E[] data;// 记录当前元素个数 Record the current number of elementsprivate int size;// 默认初始容量 Default initial capacityprivate static final int INIT_CAP = 1;public MyArrayList(){this(INIT_CAP);}public MyArrayList(int initCapability) {data = (E[])new Object[initCapability];size = 0;}/** 增**/public void addLast(E e){int cap = data.length;if (size == cap) {resize(2 * cap);}data[size] = e;size++;}public void add(int index, E e){checkPositionIndex(index);int cap = data.length;if (size == cap) {resize(2 * cap);}// move dat data[index...] -> data[index + 1..]System.arraycopy(data, index, data, index + 1, size - index);data[index] = e;size++;}public void addFirst(E e){add(0, e);}/** 删*/public E removeLast(){if (size == 0) {throw new NoSuchElementException();}int cap = data.length;if (size == cap / 4) {resize(cap / 2);}E deletedE = data[size - 1];data[size - 1] = null;size--;return deletedE;}public E remove(int index){checkElementIndex(index);int cap = data.length;if (size < cap / 4) {resize(cap / 2);}E deletedE = data[index];// move data data[index + 1....] -> data[index....]System.arraycopy(data, index + 1, data, index, size - index - 1);data[size - 1] = null;size--;return deletedE;}public E removeFirst(){return remove(0);}/** 查*/public E get(int index){checkElementIndex(index);return data[index];}/** 改*/public E set(int index, E element){checkElementIndex(index);E old = data[index];data[index] = element;return old;}/** tool method functions */public int size(){return size;}public boolean isEmpty(){return size == 0;}// 修改容量大小 Modify capacity sizepublic void resize(int newCap) {if (size > newCap) return;E[] temp = (E[])new Object[newCap];/** System.arraycopy* 四个参数:*      param1: the array to copied from*      param2: the start index in original*      param3: the array to be copied in*      param4: the total no of coponments to be copied*/System.arraycopy(data, 0, temp,0 ,size);data = temp;}// Check whether there are elements in the index positionprivate boolean isElementIndex(int index) {return index >= 0 && index < size;}// Check whether elements can be added to the index position.private boolean isPositionIndex(int index) {return index >=0 && index <= size;}private void checkElementIndex(int index) {if (!isElementIndex(index)){throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);}}private void checkPositionIndex(int index) {if (!isPositionIndex(index)) {throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);}}@Overridepublic Iterator iterator(){return new Iterator() {private  int p = 0;@Overridepublic boolean hasNext() {return p != size;}@Overridepublic E next() {return data[p++];}};}private void display() {System.out.println("size = " + size + "cap = " + data.length);System.out.println(Arrays.toString(data));}public static void main(String[] args) {// 初始容量设置为 3MyArrayList arr = new MyArrayList<>(3);// 添加 5 个元素for (int i = 1; i <= 5; i++) {arr.addLast(i);}arr.remove(3);arr.add(1, 9);arr.addFirst(100);int val = (int)arr.removeLast();for (int i = 0; i < arr.size(); i++) {System.out.println(arr.get(i));}}}

链表

图解
头部添加元素
在这里插入图片描述

尾部插入
在这里插入图片描述
删除元素
在这里插入图片描述

在index对应位置插入元素
在这里插入图片描述
如果要在1的位置插入元素,首先要找到 index为 0 和 index为1的位置,然后 进行操作。
在这里插入图片描述
在这里插入图片描述
双链表实现代码

import java.util.NoSuchElementException;public class MyLinkedList {// 双链表的节点private static class Node{E val;Node next;Node prev;Node(E val){this.val = val;}}private final Node head, tail;private int size;public MyLinkedList(){this.head = new Node<>(null);this.tail = new Node<>(null);head.next = tail;tail.prev = head;this.size = 0;}/**增*/public void addFirst(E e){Node node = new Node<>(e);Node temp = head.next;// head 和 tempnode.prev = head;node.next = temp;head.next = node;temp.prev = node;size++;}public void addLast(E e){Node node = new Node<>(e);Node temp = tail.prev;// temp headnode.next = tail;node.prev = temp;tail.prev = node;temp.next = node;size++;}public void add(int index, E e){checkPositionindex(index);Node node = new Node<>(e);Node p = getNode(index);Node temp = p.prev;node.next = p;node.prev = temp;p.prev = node;temp.next = node;size++;}/**删*/public E removeFirst(){if (isEmpty()) {throw new NoSuchElementException();}Node x = head.next;Node temp = x.next;// head -> x -> temphead.next = temp;temp.prev = head;x.next = x.prev = null;size--;return x.val;}public E removeLast(){if (isEmpty()) {throw new NoSuchElementException();}Node x = tail.prev;Node temp = x.prev;// temp <-> x <-> tailtemp.next = tail;tail.prev = temp;x.prev = x.next = null;size--;return x.val;}public E remove(int index){checkElementIndex(index);Node p = getNode(index);Node prev = p.prev;Node next = p.next;// prev <-> p ;prev.next = next;next.prev = prev;p.next = p.prev = null;size--;return p.val;}/**查*/public E getFirst(){if (isEmpty()) {throw new NoSuchElementException();}return head.next.val;}public E getLast(){if (isEmpty()) {throw new NoSuchElementException();}return tail.prev.val;}public E get(int index){checkElementIndex(index);Node p = getNode(index);return p.val;}/**改*/public E set(int index, E element){checkElementIndex(index);Node p = getNode(index);E old = p.val;p.val = element;return old;}/** other utility funcations 工具函数*/public int size(){return this.size;}public boolean isEmpty(){return 0 == size;}private boolean isElementIndex(int index) {return index >= 0 && index < size;}private boolean isPositionIndex(int index) {return index >=0 && index <= size;}// 检查index索引位置是否可以存在元素// Check whether the element can exist at the index positionprivate void checkElementIndex(int index) {if (isElementIndex(index)) {throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);}}private void checkPositionindex(int index) {if (isPositionIndex(index)) {throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);}}private Node getNode(int index) {checkElementIndex(index);Node p = head.next;for (int i = 0; i < index; i++) {p = p.next;}return p;}
}

单链表实现

import java.util.NoSuchElementException;public class MyLinkedList {private static class Node {E val;Node next;Node(E val) {this.val = val;}}private final Node head, tail;private int size;public MyLinkedList(){this.head = new Node(null);this.tail = new Node(null);head.next = tail;this.size = 0;}/**增*/public void addFirst(E e){Node x = new Node<>(e);Node temp = head.next;// head -> temp// x-> tempx.next = temp;// head-> x -> temphead.next = x;size++;}public void addLast(E e){Node x = new Node<>(e);Node temp;// find the node before last nodeif (size > 0) {temp = getNode(size - 1);} else {temp = head;}// x-> tailx.next = tail;// temp -> x -> tailtemp.next = x;size++;}public void add(int index, E e){checkPositionIndex(index);if (index == size) {addLast(e);return;}Node x = new Node<>(e);Node temp;if (index >= 0) {temp = getNode(index - 1);} else {temp = head;}Node p = getNode(index);// x->px.next = p;// temp -> x -> ptemp.next = x;size++;}/**删*/public E removeFirst(){if (isEmpty()){throw new NoSuchElementException();}Node x = head.next;head.next = head.next.next;x.next = null;size--;return x.val;}public E removeLast(){if (isEmpty()){throw new NoSuchElementException();}Node p = getNode(size - 1);Node temp;if (size >= 2) {temp = getNode(size - 2);} else {temp = head;}// temp -> x -> tailtemp.next = tail;p.next = null;size--;return p.val;}public E remove(int index){checkElementIndex(index);Node p = getNode(index);Node prev;if (index >= 0) {prev = getNode(index - 1);} else {prev = head;}// prev -> p -> nextNode next = p.next;prev.next = next;p.next = null;size--;return next.val;}/**查*/public E getFirst(){if (isEmpty()) {throw new NoSuchElementException();}return head.next.val;}public E getLast(){if (isEmpty()) {throw new NoSuchElementException();}return getNode(size - 1).val;}public E get(int index){checkElementIndex(index);Node p = getNode(index);return p.val;}/**改*/public E set(int index, E element){checkElementIndex(index);Node p = getNode(index);E old = p.val;p.val = element;return old;}/**其他工具函数Other tool functions*/public int size(){return this.size;}public boolean isEmpty(){return this.size == 0;}public  boolean isElementIndex(int index){return index >= 0 && index < size;}public boolean isPositionIndex(int index){return index >= 0 && index <= size;}private void checkElementIndex(int index){if (isElementIndex(index)) {throw new IndexOutOfBoundsException("index: "+ index + ", size:" + size);}}private void checkPositionIndex(int index){if (isPositionIndex(index)) {throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);}}private Node getNode(int index){checkElementIndex(index);Node p = head.next;for (int i = 0; i < index; i++) {p = p.next;}return p;}}

Leetcode练习题

易错点 注意 add(index) 和 delete(index)的两者不同
前者检查的是position
后者检查的是index

https://leetcode.com/problems/design-linked-list

class ListNode {int val;ListNode prev, next;public ListNode(int val){this.val = val;}
}
class MyLinkedList {private final ListNode head, tail;int size;public MyLinkedList(){this.head = new ListNode(-1);this.tail = new ListNode(-1);head.next = tail;tail.prev = head;this.size = 0;}public int get(int index) {if (!checkIndex(index)) return -1;ListNode p = head.next;for (int i = 0; i < index; i++) {p = p.next;}return p.val;}public void addAtHead(int val) {ListNode x = new ListNode(val);ListNode temp = head.next;x.prev = head;x.next = temp;head.next = x;temp.prev = x;this.size++;}   public void addAtTail(int val) {ListNode x = new ListNode(val);ListNode temp = tail.prev;x.next = tail;x.prev = temp;temp.next = x;tail.prev = x;this.size++;}public void addAtIndex(int index, int val) {if (!checkPostion(index)) return;ListNode x = new ListNode(val);ListNode p = getNode(index);ListNode temp = p.prev;x.prev = temp;x.next = p;temp.next = x;p.prev = x;this.size++;}public void deleteAtIndex(int index) {if (!checkIndex(index)) return;ListNode p = getNode(index);ListNode prev = p.prev;ListNode next = p.next;prev.next = next;next.prev = prev;p.next = p.prev = null;this.size--;}private boolean checkIndex(int index) {return index >= 0 && index < size;}private boolean checkPostion(int index) {return index >= 0 && index <= size;}private ListNode getNode(int index) {ListNode p = head.next;for (int i = 0; i < index; i++) {p = p.next;}        return p;}
}

Reference

https://appktavsiei5995.pc.xiaoe-tech.com/p/t_pc/course_pc_detail/video/v_62655468e4b09dda125fa007?product_id=p_626541bbe4b0812e1790e3f8&content_app_id=&type=6

相关内容

热门资讯

小米手机安卓系统rom,功能与... 你有没有发现,最近小米手机的热度又上来了?没错,就是那个以性价比著称的小米。今天,咱们就来聊聊小米手...
安卓8.0系统自动重启,安卓8... 最近你的安卓手机是不是也遇到了一个让人头疼的问题?没错,就是那个让人抓狂的自动重启!是不是每次正在关...
安卓导航进入系统设置,解锁个性... 亲爱的手机控们,你是否曾在某个午后,手捧着你的安卓手机,突然想探索一下它的深处,看看那些隐藏在系统设...
安卓系统爱疯7,兼容与创新的双... 你知道吗?在科技圈里,最近可是有个大热门呢!那就是安卓系统和爱疯7的较量。这两大操作系统,一个自由奔...
安卓系统第9代,新一代智能系统... 你知道吗?最近科技圈可是炸开了锅,安卓系统第9代横空出世,简直让人眼前一亮!这款全新的操作系统,不仅...
安卓系统屏幕复制软件,轻松实现... 你是不是也和我一样,有时候想分享手机屏幕上的精彩瞬间,但又不知道怎么操作呢?别急,今天就来给你揭秘安...
流量充值软件安卓系统,畅享无忧... 你有没有想过,手机里的流量用完了,却不想再办新卡或者去营业厅充值?现在,有了这些神奇的流量充值软件,...
soc系统和安卓系统的区别,架... 你有没有想过,为什么你的手机里装的是安卓系统而不是soc系统呢?这两种系统各有各的特色,今天就来给你...
宝马连不上安卓系统蓝牙,宝马车... 最近有个事儿让不少宝马车主头疼不已,那就是他们的爱车竟然连不上安卓系统的蓝牙!这可真是让人摸不着头脑...
安卓系统安装gps模块,安卓系... 你有没有想过,为什么你的安卓手机在户外旅行时总是能精准地告诉你位置呢?这背后可大有学问呢!今天,就让...
安卓手机如何修复系统,安卓手机... 手机突然卡顿,系统崩溃,是不是让你头疼不已?别担心,今天就来教你几招,让你的安卓手机焕然一新!一、重...
系统更新华为安卓,引领智能科技... 亲爱的手机控们,是不是最近你的华为手机突然变得有点儿“慢吞吞”了呢?别急,这可不是你的错觉哦!华为安...
安卓系统拦截怎么解除,轻松恢复... 你是不是也遇到了安卓系统拦截的问题,心里直痒痒想要解除它呢?别急,今天就来给你详细说说怎么搞定这个小...
老式平板装安卓系统,重温经典体... 你有没有想过,那些曾经陪伴我们度过无数时光的老式平板电脑,竟然还能装上安卓系统呢?这可不是什么天方夜...
系统如何与安卓互通,技术融合与... 你有没有想过,你的手机系统竟然能和安卓系统这么默契地互通有无?这就像是一场跨越科技界的友谊赛,让我们...
安卓系统 扫码枪,安卓系统下扫... 你有没有想过,在繁忙的超市收银台,那些快速流畅的扫码操作,背后其实隐藏着一个小小的英雄——安卓系统扫...
平板插卡推荐安卓系统,安卓系统... 你有没有想过,你的平板电脑是不是也能像智能手机一样,随时随地扩充存储空间呢?没错,这就是今天我要跟你...
安卓系统固件安装失败,原因排查... 最近是不是你也遇到了安卓系统固件安装失败的问题?别急,让我来给你详细说说这个让人头疼的小麻烦,让你一...
ios系统和安卓区别,系统差异... 你有没有发现,现在手机市场上,iOS系统和安卓系统就像是一对双胞胎,长得差不多,但性格却截然不同。今...
安卓系统2.3优酷,优酷的崛起... 你有没有发现,安卓系统2.3时代的那股怀旧风?那时候,优酷可是视频界的巨头,多少人都是看着优酷长大的...