顺序表的定义&缘由
由于我们在使用数组的时候,由于C语言语法的局限性,我们不得不提前对数组的元素个数进行规定
但是很多时候我们对数据个数的估计都是存在偏差的,估计少了会造成数组的越界,估计多了会造成内存的浪费,于是我们采用结构体+指针的方法实现一个可以自己动态开辟空间的数组,并且可以实现一定的“增删查改排…”等功能,我们称之为“顺序表”
头文件SeqList.h的书写
常用函数的预定义
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDateType;
由于我使用的是vs2022的编译器,为了防止编译器在scanf上面进行报警告,于是加上第一行代码,下面的两个include代码是包含我们常用到的函数
同时为了方便修改顺序表中的数据类型,利用typedef对int类型进行重命名
顺序表结构体的书写
typedef struct Seqlist
{
SLDateType* a;
int size;//表示数组中存储了多少个有效数据
int capacity;//表示数组的实际能存空间的数据容量是多大
}SL;
同时对结构体的名字进行typedef,这样可以减少代码书写时候的长度和复杂度
完成头文件中的接口函数的书写
ps:所谓接口函数,就是在头文件中进行定义的函数,用来表示我们的顺序表中需要实现的功能
void SeqListInit(SL* ps);//顺序表的初始化
void SeqListDestory(SL* ps);//顺序表的内存释放
void SeqListCheckCapacity(SL* ps);//顺序表的检测空间是否足够
void SeqListPushBcak(SL* ps, SLDateType x);//顺序表的尾插
void SeqListPopBcak(SL* ps);//顺序表的尾删
void SeqListPushFront(SL* ps, SLDateType x);//顺序表的头插
void SeqListPopFront(SL* ps);//顺序表的头删
int SeqListFind(SL* ps, SLDateType x);//顺序表的查找功能
void SeqListInsert(SL* ps, int pos, SLDateType x);//顺序表在表内插入功能
void SeqListErase(SL* ps, int pos);//顺序表在表内删除功能
void SeqListCheck(SL* ps);//顺序表的去重功能
void SeqListSort(SL* ps);//顺序表的排序功能
具体函数的功能我都在代码块中进行注释了
SeqList.cpp/c文件的书写
在这个文件中,我们需要实现上面的每个接口函数
顺序表的初始化
void SeqListInit(SL* ps)
{
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
顺序表的内存销毁
void SeqListDestory(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
顺序表的检查是否需要扩容
void SeqListCheckCapacity(SL* ps)
{
//如果没有空间或者空间不足我们就扩容
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);//在函数内部结束程序不能用return而要用exit(-1)
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
顺序表的尾插数据
void SeqListPushBcak(SL* ps, SLDateType x)//尾插数据
{
SeqListCheckCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
}
顺序表的尾删数据
void SeqListPopBcak(SL* ps)
{
//ps->a[ps->size - 1] = 0; //这一句可要可不要
//要注意size不可以小于0,即顺序表为空后不可以再继续--
if(ps->size > 0)
{
ps->size--;//size标识我们存了多少个有效数据,只要让size--那么有意义的数字就会减少一个
}
}
顺序表的头插数据
void SeqListPushFront(SL* ps, SLDateType x)
{
SeqListCheckCapacity(ps);
//挪动数据
int end = ps->size - 1;
while (end >= 0)
{
ps->a[end+1] = ps->a[end];
end--;
}
ps->a[0] = x;
ps->size++;
}
顺序表的头删数据
void SeqListPopFront(SL* ps)
{
//ps->size--; //如果仅仅让size--,那么代表尾删
assert(ps->size > 0);
int begin = 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
}
顺序表的查找功能
int SeqListFind(SL* ps, SLDateType x)
{
int i = 0;
for (i = 0;i < ps->size;i++)
{
if (ps->a[i] == x)
{
return i;
}
}
return -1;
}
顺序表的指定位置插入功能
void SeqListInsert(SL* ps, int pos, SLDateType x)
{
printf("请输入需要插入的下标:>");
scanf("%d", &pos);
if (pos > ps->size - 1)
{
printf("需要插入的下标不存在\n");
}
else
{
int i = 0;
int tmp = 0;
SeqListCheckCapacity(ps);
printf("请输入需要插入的元素为:>");
scanf("%d", &x);
for (i = ps->size-1;i >= pos;i--)
{
ps->a[i + 1] = ps->a[i];
}
ps->a[pos] = x;
ps->size++;
}
}
顺序表的指定位置删除功能
void SeqListErase(SL* ps, int pos)
{
printf("请输入需要删除的下标:>");
scanf("%d", &pos);
if (pos > ps->size - 1)
{
printf("需要删除的下标不存在\n");//default子句的定义
}
else
{
int i = 0;
int tmp = 0;
for (i = pos;i < ps->size;i++)
{
ps->a[i] = ps->a[i + 1];//用后一个的数据覆盖前一个来实现删除
}
ps->size--;
}
}
顺序表的查重功能
void SeqListCheck(SL* ps)//这里采用的方法是如果遇到相同的数据,就把数组往前面挪,用来覆盖数据
{
int i = 0;
int j = 0;
int k = 0;
for (i = 0;i < ps->size - 1;i++)
{
for (j = i + 1;j < ps->size;j++)
{
if (ps->a[i] == ps->a[j])
{
for (k = j;k < ps->size - 1;k++)
{
ps->a[k] = ps->a[k + 1];
}
ps->size--;//数组的元素个数减少
j--;//从j+1后面的位置一直依次向钱挪 j位置被换了新值,所以--j还要再次看
}
}
}
}
顺序表的排序功能
void SeqListSort(SL* ps)//这里采用的是冒泡排序的方法
{
int i = 0;
int j = 0;
for (i = 0;i < ps->size;i++)
{
for (j = 0;j < ps->size - 1 - i;j++)
{
if (ps->a[j] > ps->a[j + 1])
{
int tmp = 0;
tmp = ps->a[j];
ps->a[j] = ps->a[j + 1];
ps->a[j + 1] = tmp;
}
}
}
}
main函数的书写
菜单的书写
void menu()
{
printf("********************\n");
printf("********************\n");
printf("1、头插****2、头删***\n");
printf("3、尾插****4、尾删***\n");
printf("5、中插****6、中删***\n");
printf("7、查找****8、展示***\n");
printf("9、去重***10、排序***\n");
printf("******0、退出*******\n");
printf("********************\n");
printf("********************\n");
printf("*******请选择你的操作:>");
}
switch语句main函数
int main()
{
int input = 0;
SL sl;
SeqListInit(&sl);
int i = 0;
//menu();
//TestSeqList1();
//TestSeqList2();
//TestSeqList3();
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
{
printf("请输入需要插入的数据:>");
scanf("%d", &i);
SeqListPushFront(&sl, i);
break;
}
case 2:
{
SeqListPopFront(&sl);
break;
}
case 3:
{
printf("请输入需要插入的数据:>");
scanf("%d", &i);
SeqListPushBcak(&sl, i);
break;
}
case 4:
{
SeqListPopBcak(&sl);
break;
}
case 5:
{
int x = 0;
int y = 0;
SeqListInsert(&sl, x, y);
break;
}
case 6:
{
SeqListErase(&sl, i);
break;
}
case 7:
{
printf("请输入需要查找的元素:>");
scanf("%d", &i);
printf("\n");
int ans = SeqListFind(&sl, i);
printf("该元素的下标为%d\n", ans);
break;
}
case 8:
{
SeqListPrint(&sl);
break;
}
case 9:
{
SeqListCheck(&sl);
SeqListPrint(&sl);
break;
}
case 10:
{
SeqListSort(&sl);
SeqListPrint(&sl);
break;
}
default:
{
printf("输入错误,请重新输入\n");
break;
}
}
} while (input);
SeqListDestory(&sl);
return 0;
}
最后完整的代码
SeqList.h文件
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDateType;
typedef struct Seqlist
{
SLDateType* a;
int size;//表示数组中存储了多少个有效数据
int capacity;//表示数组的实际能存空间的数据容量是多大
}SL;
void SeqListPrint(SL* ps);
//接口函数
void SeqListInit(SL* ps);
void SeqListDestory(SL* ps);
void SeqListCheckCapacity(SL* ps);
void SeqListPushBcak(SL* ps, SLDateType x);
void SeqListPopBcak(SL* ps);
void SeqListPushFront(SL* ps, SLDateType x);
void SeqListPopFront(SL* ps);
//...
//如果找到了就返回x位置的下标,没有找到就返回-1
int SeqListFind(SL* ps, SLDateType x);
//在顺序表指定的下标位置插入
void SeqListInsert(SL* ps, int pos, SLDateType x);
//删除pos位置的数据
void SeqListErase(SL* ps, int pos);
//除去重复的数据
void SeqListCheck(SL* ps);
//排序顺序表中的数据
void SeqListSort(SL* ps);
SeqList.cpp文件的书写
#include "SeqList.h"
void SeqListInit(SL* ps)
{
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
void SeqListDestory(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
void SeqListCheckCapacity(SL* ps)
{
//如果没有空间或者空间不足我们就扩容
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);//在函数内部结束程序不能用return而要用exit(-1)
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
void SeqListPrint(SL* ps)
{
int i = 0;
for (i = 0;i < ps->size;i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
void SeqListPushBcak(SL* ps, SLDateType x)//尾插数据
{
SeqListCheckCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
}
void SeqListPopBcak(SL* ps)
{
//ps->a[ps->size - 1] = 0; //这一句可要可不要
//要注意size不可以小于0,即顺序表为空后不可以再继续--
if(ps->size > 0)
{
ps->size--;//size标识我们存了多少个有效数据,只要让size--那么有意义的数字就会减少一个
}
}
void SeqListPushFront(SL* ps, SLDateType x)
{
SeqListCheckCapacity(ps);
//挪动数据
int end = ps->size - 1;
while (end >= 0)
{
ps->a[end+1] = ps->a[end];
end--;
}
ps->a[0] = x;
ps->size++;
}
void SeqListPopFront(SL* ps)
{
//ps->size--; //如果仅仅让size--,那么代表尾删
assert(ps->size > 0);
int begin = 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
}
int SeqListFind(SL* ps, SLDateType x)
{
int i = 0;
for (i = 0;i < ps->size;i++)
{
if (ps->a[i] == x)
{
return i;
}
}
return -1;
}
void SeqListInsert(SL* ps, int pos, SLDateType x)
{
printf("请输入需要插入的下标:>");
scanf("%d", &pos);
if (pos > ps->size - 1)
{
printf("需要插入的下标不存在\n");
}
else
{
int i = 0;
int tmp = 0;
SeqListCheckCapacity(ps);
printf("请输入需要插入的元素为:>");
scanf("%d", &x);
for (i = ps->size-1;i >= pos;i--)
{
ps->a[i + 1] = ps->a[i];
}
ps->a[pos] = x;
ps->size++;
}
}
void SeqListErase(SL* ps, int pos)
{
printf("请输入需要删除的下标:>");
scanf("%d", &pos);
if (pos > ps->size - 1)
{
printf("需要删除的下标不存在\n");
}
else
{
int i = 0;
int tmp = 0;
for (i = pos;i < ps->size;i++)
{
ps->a[i] = ps->a[i + 1];
}
ps->size--;
}
}
void SeqListCheck(SL* ps)
{
int i = 0;
int j = 0;
int k = 0;
for (i = 0;i < ps->size - 1;i++)
{
for (j = i + 1;j < ps->size;j++)
{
if (ps->a[i] == ps->a[j])
{
for (k = j;k < ps->size - 1;k++)
{
ps->a[k] = ps->a[k + 1];
}
ps->size--;
j--;//从j+1后面的位置一直依次向钱挪 j位置被换了新值,所以--j还要再次看
}
}
}
}
void SeqListSort(SL* ps)
{
int i = 0;
int j = 0;
for (i = 0;i < ps->size;i++)
{
for (j = 0;j < ps->size - 1 - i;j++)
{
if (ps->a[j] > ps->a[j + 1])
{
int tmp = 0;
tmp = ps->a[j];
ps->a[j] = ps->a[j + 1];
ps->a[j + 1] = tmp;
}
}
}
}
main.c文件的书写
//写一个类似通讯录的菜单
void menu()
{
printf("********************\n");
printf("********************\n");
printf("1、头插****2、头删***\n");
printf("3、尾插****4、尾删***\n");
printf("5、中插****6、中删***\n");
printf("7、查找****8、展示***\n");
printf("9、去重***10、排序***\n");
printf("******0、退出*******\n");
printf("********************\n");
printf("********************\n");
printf("*******请选择你的操作:>");
}
int main()
{
int input = 0;
SL sl;
SeqListInit(&sl);
int i = 0;
//menu();
//TestSeqList1();
//TestSeqList2();
//TestSeqList3();
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
{
printf("请输入需要插入的数据:>");
scanf("%d", &i);
SeqListPushFront(&sl, i);
break;
}
case 2:
{
SeqListPopFront(&sl);
break;
}
case 3:
{
printf("请输入需要插入的数据:>");
scanf("%d", &i);
SeqListPushBcak(&sl, i);
break;
}
case 4:
{
SeqListPopBcak(&sl);
break;
}
case 5:
{
int x = 0;
int y = 0;
SeqListInsert(&sl, x, y);
break;
}
case 6:
{
SeqListErase(&sl, i);
break;
}
case 7:
{
printf("请输入需要查找的元素:>");
scanf("%d", &i);
printf("\n");
int ans = SeqListFind(&sl, i);
printf("该元素的下标为%d\n", ans);
break;
}
case 8:
{
SeqListPrint(&sl);
break;
}
case 9:
{
SeqListCheck(&sl);
SeqListPrint(&sl);
break;
}
case 10:
{
SeqListSort(&sl);
SeqListPrint(&sl);
break;
}
default:
{
printf("输入错误,请重新输入\n");
break;
}
}
} while (input);
SeqListDestory(&sl);
return 0;
}
本文有少许内容参考网上的其他代码