顺序表
线性表的顺序存储又称为顺序表,逻辑上相邻的两个元素在物理位置上也相邻。
顺序表的特点:表中元素的逻辑顺序与其物理顺序相同。
(1). 顺序表的实现——静态分配
静态分配:由于数组的大小和空间是事先已经固定,一旦空间占满,再加入新的是数据就会产生溢出,进而导致程序崩溃。
elemtype数据类型包括:整型(int)、字符串型(char)、浮点型(float)、或用户自定义型
#define Maxsize 50 //定义了最大长度
typedef struct{
ElemType data[Maxsize];//顺序表的元素
int length;//当前顺序表的长度
}SqList;
具体代码实现:
#include<stdio.h>
#define MaxSize 50 //定义了最大长度
typedef struct{
int data[MaxSize];//顺序表的元素
int length;//当前顺序表的长度
}SqList; //定义顺序表的类型(静态分配方式)
void InitList(SqList &L){//初始化顺序表
for(int i=0;i<MaxSize;i++)
L.data[i]=0;//将当前顺序表中的元素都设为0
L.length=0;//顺序表初始长度为0
}
int main(){
SqList L; //声明一个顺序表
InitList(L);//初始化顺序表
return 0;
}
(2). 顺序表的实现——动态分配
动态分配:存储的数组的空间是在程序执行过程中通过动态存储分配语句分配的,一旦数据空间占满,就另外开辟一块更大的存储空间,用以替换原来的存储空间,从而达到扩充存储数组空间的目的,而不需要为线性表一次性地划分所有空间
#define InitSize 100;//定义顺序表的初始长度
typedef struct{
int *data;//只是动态分配数组的指针
int length,MaxSize;//顺序表的当前长度和最大容量
}SeqList; //顺序表的类型定义(动态分配方式)
C的初始动态分配语句为:
L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize);
或
L.data=(ElemType*)malloc(InitSize*sizeof(ElemType));
具体代码实现:
#include<stdio.h>
#include<stdlib.h> //malloc和free的头文件
#define InitSize 100//定义顺序表的初始长度
typedef struct{
int *data;//只是动态分配数组的指针
int length,MaxSize;//顺序表的当前长度和最大容量
}SeqList; //顺序表的类型定义(动态分配方式)
void InitList(SeqList &L){
//用malloc申请一片连续的存储空间
L.data=(int*)malloc(InitSize*sizeof(int));
L.length=0;
L.MaxSize=InitSize;
}
int main(){
SeqList L;
InitList(L);
return 0;
}
增加动态数组的长度
#include<stdio.h>
#include<stdlib.h> //malloc和free的头文件
#define InitSize 100//定义顺序表的初始长度
typedef struct{
int *data;//只是动态分配数组的指针
int length,MaxSize;//顺序表的当前长度和最大容量
}SeqList; //顺序表的类型定义(动态分配方式)
void InitList(SeqList &L){
//用malloc申请一片连续的存储空间
L.data=(int*)malloc(InitSize*sizeof(int)); //此时的data指针指向第一个数据
L.length=0;
L.MaxSize=InitSize;
}
void IncreateList (SeqList &L,int len){
int *p=L.data;
L.data=(int*)malloc((L.MaxSize+len)*sizeof(int));
for(int i=0;i<L.length;i++)
L.data[i]=p[i];
L.MaxSize=L.MaxSize+len;
free(p);
}
int main(){
SeqList L;
InitList(L);
IncreateList(L,5);//增加5容量
return 0;
}
(3). 顺序表的优缺点
优点:能够随机访问,即通过首地址和元素序号可在时间O(1)内找到指定的元素;
存储密度高,每个结点只存储数据元素。
缺点:顺序表逻辑上相邻的元素物理上也相邻,所以插入和删除操作需要移动大量元素。
(4). 顺序表的插入、删除、查找操作
插入操作:需要考虑算法的严谨性,当插入的元素在非法范围内,则返回false;当插入时存储空间已经满了,则返回false。
最好情况:插入到表尾,时间复杂度O(1)
最坏情况:插入到表头,时间复杂度O(n)
平均情况:时间复杂度为O(n)
bool ListInsert(SeqList &L,int i,int e){
if(i<1||i>L.length+1)
return false;
if(L.length>=L.MaxSize)
return false;
for(int j=L.length;j>=i;j--)
L.data[j]=L.data[j-1];
L.data[i-1]=e;
L.length++;
return true;
}
删除操作:
最好情况:删除表尾数据,时间复杂度O(1)
最坏情况:删除表头数据,时间复杂度O(n)
平均情况:时间复杂度O(n)
bool ListDelete(SeqList &L,int i,int &e){
if(i<1||i>L.length+1)
return false;
e=L.data[i];
for(int j=i;j<L.length;j++)
L.data[j-1]=L.data[j];
L.length--;
return true;
}
按值查找操作:
最好情况:查找的是表头元素,时间复杂度O(1)
最坏情况:查找的是表尾元素,时间复杂度O(n)
平均情况:时间复杂度O(n)
int LocateElem(SeqList &L,int e){
for(int i=0;i<L.length;i++)
if(L.data[i]=e)
return i+1;
return 0;
}