手动实现 数组和链表
创始人
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

相关内容

热门资讯

谷歌框架和安卓系统,构建智能移... 你有没有想过,为什么你的手机那么聪明,能帮你找到路线,还能帮你拍出美美的照片呢?这都要归功于一个超级...
安卓系统和oppo系统哪个流畅... 你有没有想过,手机系统哪个更流畅呢?安卓系统和OPPO系统,这两个名字听起来就让人心动。今天,咱们就...
安卓怎么用微软系统,利用微软系... 你是不是也和我一样,对安卓手机上的微软系统充满了好奇?想象那熟悉的Windows界面在你的安卓手机上...
安卓系统如何安装nfc,安卓系... 你有没有想过,用手机刷公交卡、支付账单,是不是比掏出钱包来得酷炫多了?这就得归功于NFC技术啦!今天...
ios系统可以转安卓,跨平台应... 你有没有想过,你的iPhone手机里的那些宝贝应用,能不能搬到安卓手机上继续使用呢?没错,今天就要来...
iOSapp移植到安卓系统,i... 你有没有想过,那些在iOS上让你爱不释手的app,是不是也能在安卓系统上大放异彩呢?今天,就让我带你...
现在安卓随便换系统,探索个性化... 你知道吗?现在安卓手机换系统简直就像换衣服一样简单!没错,就是那种随时随地、随心所欲的感觉。今天,就...
安卓系统安装按钮灰色,探究原因... 最近发现了一个让人头疼的小问题,那就是安卓手机的安装按钮突然变成了灰色,这可真是让人摸不着头脑。你知...
安卓7.1.1操作系统,系统特... 你知道吗?最近我在手机上发现了一个超级酷的新玩意儿——安卓7.1.1操作系统!这可不是什么小打小闹的...
安卓os系统怎么设置,并使用`... 你有没有发现,你的安卓手机有时候就像一个不听话的小孩子,有时候设置起来真是让人头疼呢?别急,今天就来...
安卓降低系统版本5.1,探索安... 你知道吗?最近安卓系统又来了一次大动作,竟然把系统版本给降到了5.1!这可真是让人有点摸不着头脑,不...
解放安卓系统被保护,解放安卓系... 你有没有想过,你的安卓手机其实可以更加自由地呼吸呢?是的,你没听错,我说的就是解放安卓系统被保护的束...
校务帮安卓系统下载,便捷校园生... 你有没有想过,你的手机里装了一个神奇的助手——校务帮安卓系统下载?没错,就是那个能让你轻松管理学校事...
安卓系统没有拼多多,拼多多崛起... 你知道吗?最近我在手机上发现了一个小小的秘密,那就是安卓系统里竟然没有拼多多这个应用!这可真是让我大...
甜城麻将安卓系统,解锁全新麻将... 你有没有听说过那个超级火的甜城麻将安卓系统?没错,就是那个让无数麻将爱好者为之疯狂的软件!今天,就让...
安卓系统卸载的软件,深度揭秘卸... 手机里的软件越来越多,是不是感觉内存不够用了?别急,今天就来教你怎么在安卓系统里卸载那些不再需要的软...
安卓系统推荐好游戏,畅享指尖乐... 手机里的游戏可是咱们休闲娱乐的好伙伴,尤其是安卓系统的用户,选择面那可是相当广呢!今天,就让我来给你...
王者安卓系统怎么卖,揭秘如何轻... 你有没有听说最近王者安卓系统的火爆程度?没错,就是那个让无数玩家沉迷其中的王者荣耀!今天,我就来给你...
安卓开发系统内置证书,基于安卓... 你有没有想过,你的安卓手机里那些神秘的内置证书,它们到底是个啥玩意儿?别急,今天就来给你揭秘这些隐藏...
荣耀安装安卓原生系统,深度体验... 你知道吗?最近荣耀手机界可是掀起了一股热潮,那就是——荣耀安装安卓原生系统!这可不是什么小打小闹,而...