顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般分为:
1.静态顺序表:使用定长的数组存储;
2.动态顺序表:使用动态开辟的数组存储;
由于静态顺序表相对简单,我们便以动态顺序表为例来实现顺序表的相关接口;
首先是顺序表结构体的定义:
一般来说顺序表的结构体中主要包含:用于存储数据的数组,用于记录末尾数据下标(还能记录有效数据个数)的size,和动态开辟数组空间总容量的capicity;代码如下:
typedef int SLDataType;
typedef struct{
SLDataType* array; //动态开辟数组空间
int size; //有效数据的个数
int capicity; //总容量的大小
}SList;
然后是基本的增删查改接口的实现:
//初始化顺序表
void SeqListInit(SList* sl, int capicity){
assert(sl);
assert(capicity != 0);
sl->capicity = capicity;
sl->array = (SLDataType *)malloc(sizeof(SLDataType) * sl->capicity);
sl->size = 0;
assert(sl->array);
}
//销毁顺序表
void SeqListDestory(SList* sl){
assert(sl);
free(sl->array);
sl->size = 0;
sl->capicity = 0;
}
//扩容
void CheckCapacity(SList* sl){
assert(sl);
if (sl->size == sl->capicity){
sl->capicity *= 2;
realloc(sl->array, sizeof(SLDataType)* sl->capicity);
}
}
//尾插
void SeqListPushBack(SList* sl, SLDataType x){
assert(sl);
CheckCapacity(sl);
sl->array[sl->size] = x;
sl->size++;
}
//尾删
void SeqListPopBack(SList* sl){
assert(sl);
assert(sl->size > 0);
sl->size--;
}
//头插
void SeqListPushFront(SList* sl, SLDataType x){
assert(sl);
CheckCapacity(sl);
for (int i = sl->size; i > 0; i--){
sl->array[i] = sl->array[i - 1];
}
sl->array[0] = x;
sl->size++;
}
//头删
void SeqListPopFront(SList* sl){
assert(sl);
assert(sl->size > 0);
for (int i = 1; i < sl->size; i++){
sl->array[i - 1] = sl->array[i];
}
sl->size--;
}
//查找
int SeqListFind(SList* sl, SLDataType x)
{
assert(sl);
for (int i = 0; i < sl->size; i++){
if (sl->array[i] == x){
return i;
}
}
return -1;
}
//修改
void SeqListModify(SList* sl, int pos, SLDataType x){
assert(sl);
assert((pos >= 0) && (pos < sl->size));
sl->array[pos] = x;
}
完成基本接口的实现以后可以感受到,在顺序表的相关接口实现过程中,size的地位是非常高的,它是解决大部分问题的关键。其次我们可以看出,实现顺序表的尾插和尾删是非常容易的,他们的时间复杂度为O(1);而头插和头删因为需要遍历整个数组所以时间复杂度为O(N)。
接下来我们可以拓展实现一些其他的接口:
打印顺序表:
void SeqListPrint(SList* sl){
assert(sl);
for (int i = 0; i < sl->size; i++){
printf("%d ", sl->array[i]);
}
printf("\n");
}
定点插入接口:
void SeqListInsert(SList* sl, int pos, SLDataType x){
assert(sl);
assert((pos >= 0) && (pos <= sl->size));
CheckCapacity(sl);
for (int i = sl->size; i>pos; i--){
sl->array[i] = sl->array[i - 1];
}
sl->array[pos] = x;
sl->size++;
}
定点删除接口:
void SeqListErase(SList* sl, int pos){
assert(sl);
assert((pos >= 0) && (pos < sl->size));
for (int i = pos + 1; i < sl->size; i++){
sl->array[i - 1] = sl->array[i];
}
sl->size--;
}
删除指定的数:
void SeqListRemove(SList* sl, SLDataType x){
assert(sl);
int pos = SeqListFind(sl, x);
if (pos != -1){
SeqListErase(sl, pos);
}
}
冒泡排序:
void SeqListBubbleSort(SList* sl){
assert(sl);
for (int i = 1; i < sl->size; i++){
int out = 1;
for (int j = 0; j < sl->size - i; j++){
if (sl->array[j] > sl->array[j + 1]){
int t = sl->array[j];
sl->array[j] = sl->array[j + 1];
sl->array[j + 1] = t;
out = 0;
}
}
if (out == 1){
return;
}
}
}
二分法查找:
int SeqListBinaryfind(SList* sl, SLDataType x){
assert(sl);
int left = 0;
int right = sl->size - 1;
int mid;
while (left <= right){
mid = (right - left) / 2 + left;
if (x < sl->array[mid]){
right = mid - 1;
}
else if (x > sl->array[mid]){
left = mid + 1;
}
else
return mid;
}
return -1;
}
删除所有指定数:
void SeqListRemoveAll(SList* sl, SLDataType x){
assert(sl);
for (int i = 0; i < sl->size; i++){
if (sl->array[i] == x){
SeqListErase(sl, i);
}
}
}