顺序表
1. 定义
在数据结构中,顺序表(Sequential List)是一种线性表,它使用一段地址连续的存储单元依次存储线性表的数据元素。这种表示方式也被称为顺序存储结构或数组表示法。
2. 基本定义和特性
定义:
顺序表是用一段地址连续的存储单元依次存储线性表的数据元素。一般情况下,顺序表采用一维数组作为存储结构。
元素关系:
在顺序表中,数据元素之间的逻辑关系由其元素的存储位置(下标)来表示。即,第i个数据元素ai的存储位置为LOC(ai) = LOC(a1) + (i-1) * k,其中k为每个元素占用的存储单元长度,LOC(a1)为第一个元素的存储位置。
基本操作:
顺序表的基本操作包括插入、删除、查找、修改和遍历等。由于顺序表采用连续存储的方式,这些操作的时间复杂度与元素的位置有关。例如,在顺序表的末尾插入或删除元素的时间复杂度为O(1),而在任意位置插入或删除元素的时间复杂度为O(n)。
3. 顺序表优点与缺点
优点:
存储密度高:顺序表在物理存储上是连续的,没有额外的空间开销。
访问速度快:通过下标可以快速地访问任意位置的元素。
缺点:
插入和删除操作需要移动大量元素:当在顺序表的非末尾位置插入或删除元素时,需要移动插入位置或删除位置之后的所有元素。
存储空间需要预先分配:顺序表的大小是固定的,需要在创建时预先分配足够的存储空间。如果存储空间不足,需要进行扩容操作,这可能会导致性能下降。
扩容:当顺序表已满且需要插入新元素时,需要进行扩容操作。扩容通常是通过重新分配一个更大的连续存储空间并将原顺序表中的数据复制到新空间来实现的。扩容操作的时间复杂度较高,因此在实际应用中需要尽量避免频繁扩容。
4. 顺序表的应用
数据结构中顺序表的应用广泛,其特点是由数组实现,支持随机访问,但插入和删除操作(非首尾位置)可能效率较低。以下是顺序表的一些主要应用场景,结合参考文章中的信息进行归纳:
4.1实现数组
顺序表本身就是一种特殊的数组,可以直接用于实现数组结构,支持随机访问和快速查找。
4.2实现哈希表中的开放地址法
在哈希表的设计中,当发生哈希冲突时,可以使用开放地址法解决冲突,其中顺序表可以作为开放地址法的一种存储结构。
4.3实现排序算法
顺序表可以用于实现大部分排序算法,如冒泡排序、插入排序、选择排序、希尔排序、快速排序、归并排序等。这些排序算法直接对数组进行操作,而顺序表本质上就是数组。
4.4实现静态链表
使用数组来模拟链表的操作,可以在空间和时间上做出平衡。这种链表称为静态链表,它使用顺序表的一部分空间来存储链表的节点,用游标代替指针表示节点间的逻辑关系。
4.5播放列表
播放列表是一种特殊的顺序表,用于存储音视频文件的播放顺序。它支持添加文件、删除文件、播放下一个、播放上一个等操作,并可以实现随机播放、单曲循环、列表循环等播放模式。
4.6菜单系统
菜单系统,如餐厅点餐系统或自助售货机界面,可以使用顺序表来存储菜单项的顺序。系统可以实现添加菜单项、删除菜单项、显示下一个菜单项、显示上一个菜单项等操作,并可以支持菜单项的排序和查找功能。
4.7静态数据存储
在一些需要频繁访问但不需要频繁修改数据的场景中,可以使用顺序表来存储这些数据。例如,一些配置信息、常量数据或静态资源等。
4.8作为其他数据结构的底层实现
顺序表还可以作为其他复杂数据结构的底层实现,如栈、队列、哈希表等。通过在这些数据结构中使用顺序表作为存储容器,可以简化实现并提高性能
5. 顺序表操作
//_新增元素,默认在数组最后新增
public void add(int data) { }
// 在 pos 位置新增元素
public void add(int pos, int data) { }
// 判定是否包含某个元素
public boolean contains(int toFind) { return true, }
// 查找某个元素对应的位置
public int indexOf(int toFind) { return -1; }
// 获取 pos 位置的元素
public int get(int pos) { return -1; }
// 给 pos 位置的元素设为 value
public void set(int pos, int value){ }
//删除第一次出现的关键字key
public void remove(int toRemove){}
// 获取顺序表长度
public int size() { return 0; }
// 清空顺序表
public void clear() {}
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看试结果给出的
public void display(){}
6. 方法实现
创建顺序表
public class SeqList {
private int[] array;
public static final int Current_Max=5; //当前数组元素最大值
private int UsedSize; //记录当前顺序表中有多少个有效的数据
public SeqList() {
this.array = new int[Current_Max];
}
}
1. 打印数组
public static void DisPlay(){
for(int i=0;i<SeqList.Current_Max;i++){
System.out.printf(array[i]+" ");
}
2. 新增元素
默认在数组最后新增
public void add(int data){
if(isFull()){
array= Arrays.copyOf(array,2*array.length);
}
array[UsedSize]=data;
UsedSize++;
}
提供的 add 方法是一个向顺序表中添加整数元素的示例,该方法在顺序表满时会扩容。
3. 获取 pos 位置的元素
public int get(int pos){
if(pos<0||pos>=UsedSize){
throw new PosOutBoundsException("获取数据时,位置不合法!");
}
return array[pos];
}
自定义异常
public class PosOutBoundsException extends RuntimeException {
public PosOutBoundsException() {
}
public PosOutBoundsException(String message) {
super(message);
}
}
4. 判定是否包含某个元素
public boolean contains(int toFind) { return true, }
public boolean contains(int toFind){
for(int i=0;i<SeqList.Current_Max;i++)
{
if(toFind==array[i]){
return true;
}
}
return false;
}
5. 查找某个元素对应的位置
public int indexOf(int toFind) { return -1; }
public int indexOf(int toFind){
for(int i=0;i<SeqList.Current_Max;i++)
{
if(toFind==array[i]){
System.out.printf("该元素对应下标为"+i+"\n");
}
}
return -1;
}
6. 在pos位置新增元素
public void add(int pos,int data) {
//判断位置是否合法,要符合顺序表的逻辑连续
if(pos<0||pos>UsedSize){
throw new PosOutBoundsException("pos位置不合法");
}
//判满
if(isFull()){
array= Arrays.copyOf(array,2*array.length);//扩容
}
//挪数据
for(int i=UsedSize-1;i>=pos;i--)
{
array[i+1]=array[i];
}
//存数据
array[pos]=data;
UsedSize++;
}
7. 给pos位置元素设为value【更新】
public void set(int pos,int value){
if(!checkPos(pos)){
throw new PosOutBoundsException("获取数据时,位置不合法!");
}
array[pos]=value;
}
判断pos是否合法
private boolean checkPos(int pos){
if(pos<0||pos>=UsedSize){
return false;
}
return true;
}
自定义报错
public class PosOutBoundsException extends RuntimeException {
public PosOutBoundsException() {
}
public PosOutBoundsException(String message) {
super(message);
}
}
8. 删除第一次出现的关键字key
public void remove(int toRemove){
if(isEmety()){
return;
}
int index=indexOf(toRemove);//找到要删除的数据下标
if(index==-1){
return;
}
for(int i=index;i>UsedSize-1;i++){
array[i]=array[i+1];
}
UsedSize--;
}
判空
public boolean isEmety(){
return UsedSize==0;
}
9. 获取顺序表长度
public int size(){
return usedSize;
}
10. 清空顺序表
public void clear(){
UsedSize=0;
}