1、线性表
是n个具有相同特性的数据元素的有限序列,线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的一条直线,但是物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
2、顺序表
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。 顺序表就是数组,但是在数组的基础上,他还要求数据是连续存储的,不能跳跃间隔
顺序表一般可以分为:
1、静态顺序表:一次给固定的值,不能改变
#define N 100
typedef int SLDataType;
typedef struct SeqStaList
{
SLDataType data[N];
size_t size;
}SeqSTList;
2、动态顺序表:可以随着数据的增加而扩大容量。
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a;
int size; //表示数组中存了多少个数据
int capacity;//容量
}SL;
顺序表的缺陷:
1、空间不够需要增容,增容的代价比较大
2、空间会浪费
3、连续的空间,插入数据的时候需要依次移动数据,效率不高。
动态顺序表的部分操作:
1、动态顺序表的初始化
void SeqListInit(SL* ps)
{
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
2、扩容。
在插入数据时,需要判断顺序表内存放的数据是否达到容量,如果顺序表满了,就会存在栈溢出的风险。采用realloca函数,在第一次扩容时,当指针的内容为空时,realloca的功能和molloc的功能是一样的。所扩的容量是上一次的两倍。在初次扩容的时候,要判断容量的大小,因为在初始化的时候,容量为0,所以要给容量赋初值。
void SeqListCheckList(SL* ps)
{
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1); //直接终止程序
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
3、打印
void SeqListPrint(SL* ps)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
4、尾插。
从顺序表的最后插入一个数据。再插入数据的时候要判断是否扩容。
// 尾插
void SeqListPushBack(SL* ps, SLDataType x)
{
SeqListCheckList(ps);
ps->a[ps->size] = x;
ps->size++;
}
5、尾删。
尾删不用删除数组中的数据,而是直接让元素数量减一就可,这样就不会打印最后一个值。但是要判断该顺序表中是否有数据。
//尾删
void SeqListPopBack(SL* ps)
{
assert(ps->size > 0); //条件为假,直接终止程序
ps->size--;
}
6、头插
在数据的开头插入一个值。首先要判断容量是否足够,其次要挪动数据,从后往前挪,如果从前往后挪,则数据会被覆盖。
void SeqListPushFront(SL* ps, SLDataType x)
{
SeqListCheckList(ps);
int end = ps->size - 1;
while (end >= 0)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps->a[0] = x;
ps->size++;
}
7、头删
删除最前面的数据,后面的数据要往前面挪一个单位。只能从前往后挪。
void SeqListPopFront(SL* ps)
{
assert(ps->size > 0);
int begin = 0;
while (begin < (ps->size - 1))
{
ps->a[begin] = ps->a[begin + 1];
begin++;
}
ps->size--;
}
8、找值
因为插入的值都是随机的,所以直接采用for循环遍历就好。
//找到了返回x位置下标,没有找到返回-1
//找值
int SeqListFind(SL* ps, SLDataType x)
{
int i =0 ;
for (i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
{
return i;
}
}
return -1;
}
9、指定下标插入数据
先判断是否要增容,接着要挪动数据从后往前挪,直到插入数据的位置停止。
void SeqListInsert(SL* ps, int pos, SLDataType x)
{
SeqListCheckList(ps);
if (pos > ps->size|| pos<0)
{
printf("pos invalid\n");
/*exit(-1);*/
return; //温柔处理方式
}
else
{
int end=ps->size-1;
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
--end;
}
ps->a[pos] = x;
ps->size++;
}
}
10、指定下标位置删除
从下标位置向后挪动数据。
// 指定pos下标位置删除
void SeqListErase(SL* ps, int pos)
{
if (pos > ps->size || pos < 0)
{
printf("该下标位置错误\n");
exit(-1);
}
else
{
while (pos < ps->size)
{
ps->a[pos] = ps->a[pos + 1];
pos++;
}
ps->size--;
}
}
11、菜单
enum OPTION
{
EXIT,
PushFront,
PushBack,
Inser,
PopFront,
PopBack,
Erase,
Find,
Print
};
//写类似的一个菜单
void menu()
{
printf("*****************************************\n");
printf("********1、头插 2、尾插************\n");
printf("********3、定插 4、头删 ************\n");
printf("********5、尾删 6、定删 ************\n");
printf("********7、找值 8、打印************\n");
printf("******** 0、离开 ************\n");
printf("*****************************************\n");
}
void TestSeqList3()
{
SL sl;
SeqListInit(&sl);
int input = 0;
int n = 0;
int pos = 0;
do
{
menu();
printf("请选择:>\n");
scanf("%d", &n);
switch (n)
{
case PushFront:
{
printf("请输入插入的值:>\n");
scanf("%d", &input);
SeqListPushFront(&sl, input);
break;
}
case PushBack:
{
printf("请输入插入的值:>\n");
scanf("%d", &input);
SeqListPushBack(&sl, input);
break;
}
case Inser:
{
printf("请输入插入的值的下标:>\n");
scanf("%d", &pos);
printf("请输入插入的值:>\n");
scanf("%d", &input);
SeqListInsert(&sl, pos, input);
break;
}
case PopFront:
{
SeqListPopFront(&sl);
break;
}
case PopBack:
{
SeqListPopBack(&sl);
break;
}
case Erase:
{
printf("请输入要删除的下标:>\n");
scanf("%d", &pos);
SeqListErase(&sl, pos);
break;
}
case Find:
{
printf("请输入查找的值:>\n");
scanf("%d", &input);
int ret = SeqListFind(&sl, input);
if (ret != -1)
{
printf("该值的下标为%d\n", ret);
}
else
{
printf("不存在该值\n");
}
break;
}
case Print:
{
SeqListPrint(&sl);
break;
}
case EXIT:
{
SeqListDestory(&sl);
printf("成功退出\n");
break;
}
}
} while (n);
}
int main()
{
TestSeqList3();
return 0;
}