看前技术需求:熟悉C++或Java语言,并且知道数组是个什么东东。ΦωΦ
看前声明:本人只是一个在校大学生,算法蒟蒻。发表这篇文章也只是记录自己的所思所想。且这篇文章会以应用为主,也就是尽量用最少的语言说清楚如何实现。相信屏幕前一定有许多大佬。若有更好的解决办法,望不吝赐教。若有错误部分,也请指出,不胜感激。ww
但请轻喷,要脸TAT
----------------我是分割线-------------------
正文第一行用来膜拜大佬们。膜拜膜拜膜拜我磕磕磕磕 ○| ̄|_
关于顺序表和数组
(此处在抄书,熟悉的友友可以直接略过) 线性表是数据结构中的一种基本形式,它是由n个类型相同的元素组成的有限序列。线性表中的每个元素都有且只有一个直接前驱和一个直接后继(除了第一个元素没有前驱,最后一个元素没有后继)。顺序表是一种具体的线性表实现方式,它使用一段地址连续的存储单元依次存储线性表的数据元素,并且按照元素在线性表中的逻辑次序存放。
在计算机科学中,数组是一种存储多个相同类型数据的容器,这些数据存放在内存中连续的位置,并且可以通过索引(通常是整数)来访问它们。由于数组的特点与顺序表的存储方式非常相似,因此可以说顺序表是通过数组来实现的一种数据结构。
总结来说,顺序表可以理解为用数组实现的线性表,在顺序表中,数组的下标反映了元素之间的逻辑关系。但是虽然顺序表通常由数组实现,但这并不是唯一的方法。
相信点进来的友友们都知道数组是啥了吧......那么这边就不再啰嗦数组的定义了,直接就说怎么进行增删改查。
一,查
对于数组来说,查询元素是最简单的操作。因为只需要知道数组的下标,就可以读取到相应的数组元素。
例:众所周知,数组的英文为array。假设现在有一个数组array,我想要读取下标为10的元素,就写作array[10]即可。但需要注意,不可以读取数组容量之外的元素。也就是说,假设一个数组只开了10个空间,那么array[15]是不可以去读取的,否则就会出现数组越界而返回未知的错误数据。
以下是简单的代码实现
c++实现↓
int array[] = {1,2,3,4,5,6,7,8,9,10};
//输出下标为9的元素,也是数组中的第10个元素
cout << array[9];
java实现↓
int[] array = new int[]{1,2,3,4,5,6,7,8,9,10};
//输出下标为9的元素,也是数组中的第10个元素
System.out.println(array[9]);
二,改
把数组中的某个元素改为一个新值,只需要知道数组的下标,之后把新值赋给对应的数组下标即可。
c++实现
int array[] = {1,2,3,4,5,6,7,8,9,10};
//将下标为0的数据改为100
int array[0] = 100;
cout << array[0] ;
java实现
int[] array = {1,2,3,4,5,6,7,8,9,10};
//将下标为0的数据改为10
array[0] = 10;
System.out.println(array[0]);
另外一说,数组中的“查”和“改”操作,时间复杂度只有O(1),是很高效的操作。
三,删
如果删除的元素位于数组的中间,那么后面的元素就应该往前挪一位,如下图
下面是c++的实现代码,注释什么的都写好了
#include <iostream>
using namespace std ;
/////////////////////////////////////////////////////////////////
//下面的这个代码块就是删除元素操作的具体实现ww
/*
Q:此处totalsize为何要用引用“&”的形式?
E:如果不用,那么在deletedata中totalsize的操作无法反映到主函数中。所以用引用后,函数里对totalsize的操作就相当于直接对主函数中的totalsize操作。能更正确地计算数组的实际大小
*/
void deletedata(int deleteindex,int &totalsize,int array[])
{
//下面这个if会检测删除的数组下标是否超过数组的实际范围,若超过则提示。
if(deleteindex <0 ||deleteindex >= totalsize)
{
cout <<"删除的数组下标超出实际数组范围!!!\n";
}
//下面这个for循环会实现“如果删除元素位于中间,其后面的元素就需要往前挪一位”的操作
for(int i = deleteindex ; i < totalsize - 1 ; i++)
{
array[i] = array[i+1] ;
}
totalsize -- ;
}
////////////////////////////////////////////////////////////////
int main()
{
int array[] = {0,1,2,3,4,5,6,7,8,9};
//下面的totalsize表示的是数组中实际拥有的元素
//"sizeof(array)/sizeof(array[0])"这行语句可以通过字节计算来计算数组长度
//PS:为啥c++现在还没法直接支持“.length”的写法啊,差评(不是) OvO
int totalsize = sizeof(array)/sizeof(array[0]);
//deleteindex表示要删除的数组下标对应的元素,比如想删除array[0],就输入0即可
int deleteindex ; cin >> deleteindex ;
deletedata(deleteindex,totalsize,array);
//下面这个for循环是在打印整个数组,以验证删除操作是否正确
for(int i = 0 ; i <totalsize ; i++)
{
cout << array[i] << " " ;
}
return 0 ;
}
下面是java的实现代码块
public int delete(int deleteindex) throws Exception
{
//判断访问下标是否超出范围
if(deleteindex<0 || deleteindex>=totalsize)
{
throw new IndexOutOfBoundsException("超出数组实际元素范围!");
}
int deletedelement = array[deleteindex];
//从左向右循环,逐个元素向左挪一位。
for(int i=deleteindex; i<totalsize-1; i++)
{ array[i] = array[i+1]; }
totalsize--;
return deletedelement; }
四,增
也可以理解为插入元素。首先我们应该知道,数组中实际元素的数量可能小于数组开出的长度,如图
而在这个情况下,一般有两种玩法“尾部插入”,“中间插入”和一个高级版玩法“溢出插入”
前两种插入的数据不能超过数组开出的容量。也就是数组一开始开了10个int空间。如果插入后元素数量超过10,会出现错误的情况。
尾部插入
因为有的时候数组的实际元素数量可能小于数组开的长度。
在这个情况下,要是想要进行尾部插入,直接就在尾部的下标中更新元素即可。在此不多赘述。
中间插入
与前文说的删除操作相反。删除操作是把“目标下标”后的元素往前移一位。
而中间插入操作则是把“目标下标”后的元素往后移一位。如图
c++实现与详细注释如下
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////////////////////
//下面的函数用来实现插入操作ww
//element表示待插入的元素,index表示插入元素对应的下标。totalsize表示数组实际元素数量。使用“&”的理由与上一节的理由相同
void insertArray(int element, int index, int array[], int &totalsize)
{
//判断插入下标是否越界
if (index < 0 || index > totalsize)
{
cout << "超过数组容纳范围!\n";
return;
}
if (totalsize == 10) // 检查是否达到最大容量
{
cout << "数组已满,无法插入新元素。\n";
return;
}
// 从最后一个元素开始,逐个把前面的元素向后移动一位。到达插入下标后停止移动
for (int i = totalsize; i > index; i--)
{
array[i] = array[i-1];
}
array[index] = element; // 在指定位置插入新元素
totalsize++; // 更新实际元素数量
}
////////////////////////////////////////////////////////////////////////////////
// 下面的函数只用来输出数组
void outputArray(int array[], int totalsize)
{
for (int i = 0; i < totalsize; i++)
{
cout << array[i] << " ";
}
}
int main()
{
//创建一个包含8个元素的数组。但数组容量为10,故有两个空位
int array[10] = {0,1,2,3,4,5,6,7} ;
int totalsize = 8;
//element是要插入元素的具体数值,index是插入的目标下标
int element;
int index;
cin >> element;cin >> index;
insertArray(element, index, array, totalsize);
outputArray(array, totalsize); // 传入实际的元素数量
return 0;
}
java代码块实现和详细注释如下
private int[] array;
private int totalsize;
public MyArray(int capacity)
{
this.array = new int[capcity];
totalsize = 0;
}
public void insert(int element, int index) throws Exception
{
//判断访问下标是否超出范围
if(index<0 || index>totalsize)
{
throw new IndexOutOfBoundsException("超出数组实际元素范围!");
}
//从右向左循环,逐个元素向右挪一位。
for(int i=totalsize-1; i>=index; i--){ array[i] = array[i-1];
}
//腾出的位置放入新元素
array[index] = element; totalsize++;
}
//输出数组
public void output()
{
for(int i = 0;i <totalsize ; i++)
{
System.out.println(array[i]);
}
}
public static void(String[] args)throws Exception
{
MyArray myArray = new MyArray(10);
myArray.insert(1,0);
myArray.insert(2,1);
myArray.insert(10,1);
myArray.output();
}
溢出插入
也叫超范围插入。 假如现在有一个长度为5的数组,并且里面填满了元素。那么接下来,若是再想添加元素,数组就会被“撑爆”,导致数据溢出。
解决问题的方法也不难(此处膜拜一下想到这个方法的人叭~)解决办法就是再创建一个新数组,长度比原数组更长(一般会长2倍)之后把原数组的元素再全都复制过去!这样就实现的数组的扩容。
下面是c++实现与详细注释
#include <iostream>
#include <algorithm>
using namespace std ;
void insertArray(int element, int index, int*& array, int& totalsize, int& capacity)
{
if (index < 0 || index > totalsize)
{
cout << "超过数组容纳范围!\n";
return ;
}
if (totalsize >= capacity) // 检查是否达到最大容量
{
int newCapacity = capacity * 2; // 新的容量是当前的两倍
int* newArray = new int[newCapacity]; // 创建新的数组
// 复制旧数组的内容到新数组
copy(array, array + totalsize, newArray);
// 释放旧数组
delete[] array;
// 更新引用
array = newArray;
capacity = newCapacity;
}
// 从最后一个元素开始,逐个向前移动直到到达插入位置。
for (int i = totalsize; i > index; i--)
{
array[i] = array[i - 1];
}
array[index] = element; // 在指定位置插入新元素
totalsize++; // 更新元素数量
}
void outputArray(int array[], int totalsize)
{
for (int i = 0; i < totalsize; i++)
{
cout << array[i] << " ";
}
}
int main()
{
int capacity = 10;
int* array = new int[capacity];
int totalsize = 0;
// 初始化数组
for (int i = 0; i < capacity; ++i)
{
array[totalsize++] = i;
}
//element--插入数值 index--插入位置
int element;
int index;
for(int i = 0 ; i< 5 ; i++)
{
cin>>element;
cin >> index;
insertArray(element, index, array, totalsize, capacity);
outputArray(array, totalsize);
}
delete[] array; // 释放动态分配的内存
return 0;
}
下面是java实现与详细注释
public class MyArray {
private int[] array;
private int size;
public MyArray(int capacity){
this.array = new int[capacity];
size = 0;
}
// 数组插入元素
// index 插入的位置
// element 插入的元素
public void insert(int index, int element) throws Exception {
//判断访问下标是否超出范围
if(index<0 || index>size){
throw new IndexOutOfBoundsException("超出数组实际元素范围!");
}
//如果实际元素达到数组容量上线,数组扩容
if(size >= array.length){
resize();
}
//从右向左循环,逐个元素向右挪一位。
for(int i=size-1; i>=index; i--){
array[i+1] = array[i];
}
//腾出的位置放入新元素
array[index] = element;
size++;
}
// 数组扩容
public void resize(){
int[] arrayNew = new int[array.length*2];
//从旧数组拷贝到新数组
System.arraycopy(array, 0, arrayNew, 0, array.length);
array = arrayNew;
}
// 输出数组
public void output(){
for(int i=0; i<size; i++){
System.out.println(array[i]);
}
}
public static void main(String[] args) throws Exception {
MyArray myArray = new MyArray(4);
myArray.insert(1,0);
myArray.insert(1,1);
myArray.insert(2,1);
myArray.insert(3,1);
myArray.insert(4,1);
myArray.insert(5,1);
myArray.output();
}
}
不过由于在数组中的删除和插入一般复杂度都是O(n)并不是太高效的方法。
所以在数组中的操作,更适合“读操作多,写操作少”的场景
它与以高效增删操作的链表相反。链表更适合“读操作少,写操作多”的场景
若有时间,这边会补充的。敬请期待叭~
尽管尽可能避免错误,但仍可能会有漏洞和不足,望屏幕前的你批评指正。