顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组
上完成数据的增删查改。
顺序表一般可以分为:1. 静态顺序表:使用定长数组存储元素。2. 动态顺序表:使用动态开辟的数组存储。
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
//初始化
void SLInit(SL *ps1);
//销毁
void SLDestroy(SL *ps1);
//打印
void SLPrint(SL* ps1);
//STL命名风格
//尾插
void SLPushBack(SL* ps1, SLDatatype x);
//头插
void SLPushFront(SL* ps1, SLDatatype x);
//尾删
void SLPopBack(SL* ps1);
//头删
void SLPopFront(SL* ps1);
//中间插入
void SLInsert(SL* ps1, int pos, SLDatatype x);
//中间删除
void SLErase(SL* ps1, int pos);
//查找
int SLFind(SL* ps1, SLDatatype x);
//修改
void SLModify(SL* ps1, int pos, SLDatatype x);
#define N 10
typedef int SLDatatype;
struct Seqlist
{
SLDatatype a[N];
int size;
};
typedef int SLDatatype;
typedef struct SeqList
{
SLDatatype* a;
int size;//存储的有效数据的个数
int capacity; //容量
}SL;
对指针初始化为空,数据个数初始化为0,数据容量动态开辟初始化为4
void SLInit(SL* ps1)
{
ps1->a = (SLDatatype*)malloc(sizeof(SLDatatype) * 4);
if (ps1->a == NULL)
{
perror("malloc fail");
return;
}
ps1->capacity = 4;
ps1->size = 0;
}
对指针置空,数据个数置0,数据容量置0
void SLDestroy(SL* ps1)
{
free(ps1->a);
ps1->a=NULL;
ps1->size = 0;
ps1->capacity = 0;
}
对顺序表的所有数据进行打印
void SLPrint(SL* ps1)
{
for (int i = 0; i < ps1->size; i++)
{
printf("%d ", ps1->a[i]);
}
printf("\n");
}
如果数据个数等于数据容量,用realloc进行2倍扩容
void SLCheckCapacity(SL* ps1)
{
if (ps1->size == ps1->capacity)
{
SLDatatype* tmp = (SLDatatype*)realloc(ps1->a, sizeof(SLDatatype) * ps1->capacity* 2);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
ps1->a = tmp;
ps1->capacity *= 2;
}
}
void SLPushBack(SL* ps1, SLDatatype x)
{
//ps1->a[ps1->size] = x;
//ps1->size++;
/*SLCheckCapacity(ps1);
ps1->a[ps1->size++] = x;*/
SLInsert(ps1, ps1->size, x);
}
void SLPushFront(SL* ps1, SLDatatype x)
{
//SLCheckCapacity(ps1);
挪动数据
//int end = ps1->size - 1;
//while (end >= 0)
//{
// ps1->a[end + 1] = ps1->a[end];
// --end;
//}
//ps1->a[0] = x;
//ps1->size++;
SLInsert(ps1, 0, x);
}
void SLPopBack(SL* ps1)
{
暴力检查
//assert(ps1->size > 0);
温柔的检查
if (ps1->size == 0)
// //return;
ps1->a[ps1->size - 1] = 0;
//ps1->size--;
SLErase(ps1, ps1->size - 1);
}
用后面的数据来覆盖前面的数据,直到start到size-2的位置
void SLPopFront(SL* ps1)
{
暴力检查
//assert(ps1->size > 0);
///*int start = 0;
//while (start < ps1->size-1)
//{
// ps1->a[start - 1] = ps1->a[start];
// start++;
//}*/
//int start = 1;
//while (start < ps1->size)
//{
// ps1->a[start - 1] = ps1->a[start];
// start++;
//}
//ps1->size--;
SLErase(ps1, 0);
}
void SLInsert(SL* ps1, int pos, SLDatatype x)
{
assert(0 <=pos && pos <= ps1->size);
SLCheckCapacity(ps1);
int end = ps1->size - 1;
while (end >= pos)
{
ps1->a[end + 1] = ps1->a[end];
--end;
}
ps1->a[pos] = x;
ps1->size++;
}
从start后面的一个位置开始往前覆盖数据,直到start为size-1
void SLErase(SL* ps1, int pos)
{
assert(0 <= pos && pos < ps1->size);
//assert(ps1->size > 0);
int start = pos + 1;
while (start < ps1->size)
{
ps1->a[start - 1] = ps1->a[start];
++start;
}
ps1->size--;
}
找到返回下标,没有找到返回-1
int SLFind(SL* ps1, SLDatatype x)
{
for (int i = 0; i < ps1->size; i++)
{
if (ps1->a[i] == x)
{
return i;
}
}
return -1;
}
对pos位置的数据进行修改
void SLModify(SL* ps1, int pos, SLDatatype x)
{
assert(0 <= pos && pos < ps1->size);
ps1->a[pos] = x;
}
void menu()
{
printf("********************************\n");
printf("*****1.尾插数据 2.尾删数据******\n");
printf("*****3.头插数据 4.头删数据******\n");
printf("*****5.打印数据 -1.退出*********\n");
printf("********************************\n");
}
int main()
{
int option = 0;
SL s;
SLInit(&s);
while (option != -1)
{
menu();
printf("请输入你的操作:");
scanf("%d", &option);
if (option == 1)
{
/*printf("请输入要尾插的数据,以-1结束:");
int x = 0;
scanf("%d", &x);
while (x != -1)
{
SLPushBack(&s, x);
scanf("%d", &x);
}*/
int n = 0;
printf("请输入要尾插的数据个数,再依次输入要插入的数据:");
scanf("%d", &n);
int x = 0;
while (n > 0)
{
scanf("%d", &x);
SLPushBack(&s, x);
n--;
}
}
else if (option == 5)
{
SLPrint(&s);
}
else if (option == -1)
{
break;
}
else
{
printf("无此选项,请重新输入");
}
}
SLDestroy(&s);
//TestSeqList1();
return 0;
}