1.什么是数据结构
2.顺序表概念及结构
3.顺序表分类
4.实现动态顺序表
1.什么是数据结构
数据结构是计算机存储、组织数据的方式。可以用来完成通讯录项目。
2.顺序表概念及结构
2.1线性表
线性表是n个具有相同特性的数据元素的有限序列
常见的线性表:顺序表,链表,栈队列,字符串
线性表在逻辑上是线性的,但在物理结构上却不一定,也就是在内存上的存储不一定是连续的
3.顺序表分类
静态顺序表:空间是固定的,给多了浪费空间,给少了空间不够
缺点多,不建议使用
动态顺序表:空间可以扩大,但扩大空间会浪费时间
相较于静态顺序表优点多,建议使用
4.实现动态顺序表
文件名:SeqList.c
#define _CRT_SECURE_NO_WARNINGS
#include "Seqlist.h"
void initSeqList(SL* pSL)//初始化顺序表
{
pSL->pa = NULL;
pSL->size = 0;
pSL->capacity = 0;
}
void cheak(SL* psl1)//检查空间是否足够
{
if (psl1->size == psl1->capacity)
expandSL(psl1);
}
void expandSL(SL* pSL)//扩容
{
int newcapacity = pSL->capacity == 0 ? 4 : 2 * pSL->capacity;
SLdatatype* pSLm = realloc(pSL->pa, (size_t)newcapacity * sizeof * (pSL->pa));
if (pSLm == NULL)
{
perror("relloc");
exit(1);
}
else
pSL->pa = pSLm;
pSL->capacity = newcapacity;
}
void printSL(SL* pSL)//打印顺序表
{
assert(pSL);
int i;
for (i = 0; i < pSL->size; i++)
printf("%d ", pSL->pa[i]);
}
void backaddSL(SL* pSL, SLdatatype n)//后增
{
assert(pSL);
cheak(pSL);
pSL->pa[pSL->size++] = n;
}
void frontaddSL(SL* pSL, SLdatatype n)//前增
{
assert(pSL);
cheak(pSL);
int i;
for (i = 0; i < pSL->size; i++)
{
pSL->pa[pSL->size - i] = pSL->pa[pSL->size - i - 1];
}
pSL->pa[0] = n;
pSL->size++;
}
void backdel(SL* pSL)//后删
{
assert(pSL != NULL);
assert(pSL->size > 0);
pSL->size--;
}
void frontdel(SL* pSL)//前删
{
assert(pSL != NULL);
assert(pSL->size > 0);
int i;
for (i = 0; i < pSL->size - 1; i++)
{
pSL->pa[i] = pSL->pa[i + 1];
}
pSL->size--;
}
void posaddSL(SL* pSL, SLdatatype n, int pos)//指定位置插入
{
assert(pSL);
int i = 0;
for (i = 0; i < pSL->size - pos + 1; i++)
{
pSL->pa[pSL->size - i] = pSL->pa[pSL->size - i - 1];
}
pSL->pa[pos - 1] = n;
pSL->size++;
}
void posdelSL(SL* pSL, int pos)//指定位置删除
{
assert(pSL);
int i = 0;
for (i = 0; i < pSL->size - pos + 1; i++)
{
pSL->pa[pos - 1 + i] = pSL->pa[pos + i];
}
pSL->size--;
}
void SLfind(SL* pSL, int n)//元素查找
{
int i = 0, flag = 1;
for (i = 0; i < pSL->size; i++)
{
if (pSL->pa[i] == n)
{
printf("元素下标为%d\n", i);
flag = 0;
}
}
if (flag)
puts("没有该元素");
}
void SLalter(SL* pSL, int n, int pos)//元素修改
{
pSL->pa[pos - 1] = n;
}
void SLdesdroy(SL* pSL)//销毁
{
assert(pSL);
if (pSL->pa != NULL)
{
free(pSL->pa);
pSL->pa = NULL;
}
pSL->size = 0;
pSL->capacity = 0;
}
文件名:SeqList.h
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int SLdatatype;
typedef struct SeqList
{
SLdatatype* pa;//数组首元素地址
int size;//元素个数
int capacity;//数组容量
}SL;
//初始化顺序表
void initSeqList(SL* pSL);
//判断空间是否足够
void cheak(SL* psl1);
//扩容
void expandSL(SL* pSL);
//打印顺序表
void printSL(SL* pSL);
//后增
void backaddSL(SL* pSL, SLdatatype n);
//前增
void frontaddSL(SL* pSL, SLdatatype n);
//后删
void backdel(SL* pSL);
//前删
void frontdel(SL* pSL);
//指定位置插入
void posaddSL(SL* pSL, SLdatatype n, int pos);
//指定位置删除
void posdelSL(SL* pSL, int pos);
//元素查找
void SLfind(SL* pSL, int n);
//元素修改
void SLalter(SL* pSL, int n, int pos);
//销毁
void SLdesdroy(SL* pSL);
文件名:test.c
#define _CRT_SECURE_NO_WARNINGS
#include "Seqlist.h"
void test1(SL* psl1)//测试后增
{
backaddSL(psl1, 5);
backaddSL(psl1, 6);
backaddSL(psl1, 7);
printSL(psl1);
}
void test2(SL* psl1)//测试前增
{
frontaddSL(psl1, 5);
frontaddSL(psl1, 6);
frontaddSL(psl1, 7);
frontaddSL(psl1, 8);
frontaddSL(psl1, 9);
frontaddSL(psl1, 5);
frontaddSL(psl1, 6);
printSL(psl1);
putchar('\n');
}
void test3(SL* psl1)//测试后删
{
backdel(psl1);
printSL(psl1);
}
void test4(SL* psl1)//测试前删
{
frontdel(psl1);
printSL(psl1);
}
void test5(SL* psl1)//测试指定位置插入
{
posaddSL(psl1, 80, 3);
printSL(psl1);
}
void test6(SL* psl1)//测试指定位置删除
{
posdelSL(psl1, 3);
printSL(psl1);
}
void test7(SL* psl1)//测试元素查找
{
SLfind(psl1, 100);
}
void test8(SL* psl1)//测试元素修改
{
SLalter(psl1, 100, 3);
printSL(psl1);
}
void test9(SL* psl1)//测试销毁
{
SLdesdroy(psl1);
printSL(psl1);
}
int main()
{
SL sl1;
initSeqList(&sl1);
// test1(&sl1);
test2(&sl1);
// test3(&sl1);
// test4(&sl1);
// test5(&sl1);
// test6(&sl1);
// test7(&sl1);
// test8(&sl1);
test9(&sl1);
return 0;
}
第5行,将int重命名。
目的:若想替换代码中所有的int,可以改变第5行的int,做到一键替换
注意:capacity说明的是最多可以容纳多少个元素,不是空间的大小,单位不是字节
第六行:创建结构体存储数据
第8和第9行,通过首元素地址下标访问,可以访问到数组中的每一个元素,元素个数是为了方便访问的,体现在后面的代码实现中
第10行:设置界限,数元素个数等于数组容量,说明需要扩容,否则不能写入数据
第一步,顺序表的初始化,没什么好说的
数元素个数等于数组容量,说明需要扩容,否则不用
第18行:newcapacity说明扩容后是最多可以容纳多少个元素
现在的问题是:一次要开辟多少空间,开辟多了,那么开辟的次数就少了,可以节省时间,但浪费的空间较多。开辟少了,那么开辟的次数就多了,浪费时间,但是相对前一个可以节省时间。
所以,我们采取一个折中的办法,也是性价比较高的一个。那就是将空间扩大到原来的两倍。第一次开辟比较特殊,初始化后,空间是0,不能扩大到原来的两倍,因为0*2=0,也就是没扩大。所以,就有了第18行的写法。
第19行:要开辟的字节数应是一个元素的大小*开辟后最大元素个数
其余的写法参考动态内存管理,这里不再赘述
若传来的是空指针,会出现错误,所以,要用assert断言一下
第一步:assert防止空指针
第二步:检查空间够不够,不够就会扩容,保证在写入元素时空间大小足够
第三步:写入元素,写完后要让元素个数加一
第一步:断言
第二步:检查空间
第3步:让所有元素往后挪一格
最后:在前面写入元素,元素个数加一
第一步:断言防空指针
第二步:断言防止顺序表中没有数据
第三步:删除元素
问题:为什么这里元素个数减1就行了?
空间里会默认存随机数,所以我们无论给需删除的地方赋什么值都不合适
所以,我们只需要能正常使用就行了,假设那个元素被删除了就行了
问题:元素个数减1是不是必要的?
是的,不减会影响正常使用,体现的后面的代码中
第一步:双断言
第二步:让所有元素像前移动一格
第三步:元素个数减一
第一步:指定位置和后面的元素都向后移动一个
第二步:插入元素
第三步:元素个数加1
第一步:指定位置后面的元素往前移动一格
第二步:元素个数减一
第一步:一个一个比较,有相同的说明找到了,打印该元素的下标,使flag为0
第二步:没找到说明flag是1,打印“没找到”。
直接修改就行了,没什么好说的
第一步:assert断言
第二步:如果pa不指向NULL,说明pa是有分配空间的,free掉,并使pa指向NULL。
第三步:使元素个数和最大元素个数为0