数组和链表的区别
-
数组是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素,但是如果要在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要 增加的元素放在其中。同样的道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素。
-
链表恰好相反,链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系上一个元素有个指针指到下一个元素,以此类推,直到最后一个元素。如果要访问链表中一个元素,需要从第一个元素开始,一直找到需要的元素位置。但是增加和删除一个元素对于链表数据结构就非常简单了,只要修改元素中的指针就可以了。
-
链表的长度是按实际需要可以伸缩的,而数组的长度是在定义时要给定的,如果存放的数据个数超过了数组的初始大小,则会出现溢出现象
-
按序号查找时,数组可以随机访问,时间复杂度为O(1),而链表不支持随机访问,平均需要O(n);
-
数组在静态存储分配情形下,存储元素数量受限制,动态存储分配情形下,虽然存储空间可以扩充,但需要移动大量元素,导致操作效率降低,而且如果内存中没有更大块连续存储空间将导致分配失败; 即数组从栈中分配空间,对于程序员方便快速,但自由度小。链表存储的节点空间只在需要的时候申请分配,只要内存中有空间就可以分配,操作比较灵活高效;即链表从堆中分配空间, 自由度大但申请管理比较麻烦。
手写数组部分
/**
* @Author LWL
* @Date 2022/8/10 22:05
* @TODO 手写数组
*/
public class ArrayUtil {
private int[] element;
private int currentIndex = -1; // 记录当前数组下标
public ArrayUtil() {
this(3);
}
public ArrayUtil(int capacity) {
this.element = new int[capacity];
}
/* 新增 */
public void add(int data) {
currentIndex++;
if (currentIndex > element.length - 1) {
int[] temp = new int[element.length * 2];
for (int i = 0; i < element.length; i++) {
temp[i] = element[i];
}
element = temp; // 改变引用
}
element[currentIndex] = data;
}
/* 删除 */
public void del(int index) {
if (index < 0 || index > element.length - 1) {
throw new RuntimeException("this index [" + index + "] out of range");
}
for (int i = index; i < element.length - 1; i++) {
element[i] = element[i + 1];
}
currentIndex--;
}
/* 修改 */
public void set(int index, int data) {
if (index < 0 || index > element.length - 1) {
throw new RuntimeException("this index [" + index + "] out of range");
}
element[index] = data;
}
/* 转字符串 */
public String arrToStr() {
String result = "[";
for (int i = 0; i < currentIndex + 1; i++) {
result = result + element[i] + ",";
}
return result.substring(0, result.length() - 1) + "]";
}
/* 通过下标获取元素 */
public Integer queryByIndex(int index) {
if (index < 0 || index > element.length - 1) {
/*throw new RuntimeException("this index [" + index + "] out of range");*/
return null;
}
return element[index];
}
public int[] queryArray() {
return element;
}
/* 排序 */
public void sort() {
for (int i = 0; i < currentIndex; i++) {
for (int j = 0; j < currentIndex - i; j++) {
if (element[j] > element[j + 1]) {
int temp = element[j];
element[j] = element[j + 1];
element[j + 1] = temp;
}
}
}
}
手写链表部分
/**
* @Author LWL
* @Date 2022/8/11 0:12
* @TODO 定义节点
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Node {
private Node next; // 节点
private Integer element; // 元素
}
/**
* @Author LWL
* @Date 2022/8/12 0:10
* @TODO 手写单向链表
*/
public class LinkedUtil {
private Node headNode;
private int currentIndex = -1;
/* 头插法 (效率高,无序)*/
public void addFirst(int element) {
this.add(0, element);
}
/* 尾插法 (效率低,有序)*/
public void addLast(int element) {
this.add(currentIndex + 1, element);
}
public void add(int index, int element) {
if (headNode == null) {
headNode = new Node(element, null);
} else {
if (index == 0) {
/* 创建一个指向头部的节点 */
Node node = new Node(element, headNode);
headNode = node;
} else {
Node node = headNode;
for (int i = 0; i < index - 1; i++) {
node = node.getNext();
}
Node newNode = new Node(element, node.getNext());
node.setNext(newNode);
}
}
currentIndex++;
}
/* 删除 */
public void del(int index) {
if (index == 0) {
headNode = headNode.getNext();
} else {
Node node = headNode;
/* 找到 index - 1 节点*/
for (int i = 0; i < index - 1; i++) {
node = node.getNext();
}
/* 删除的核心 */
node.setNext(node.getNext().getNext());
}
currentIndex--;
}
/* 修改 */
public void update(int index, int element) {
Node node = headNode;
for (int i = 0; i < index - 1; i++) {
node = node.getNext();
}
node.setElement(element);
}
/* 查询 */
public int query(int index) {
Node node = headNode;
for (int i = 0; i < index - 1; i++) {
node = node.getNext();
}
return node.getElement();
}
}