【数据结构 C语言版】第一篇 顺序表
写在前面
更新情况记录:
最近更新时间 | 更新次数 |
---|---|
2022/9/24 | 1 |
参考博客以及链接:
(非常感谢这些博主们的文章,将我的一些疑问得到解决。)
参考博客链接 |
---|
总目录: |
正文部分
目录:
链表链接:
顺序表与链表总结篇链接:
0.顺序表前置C语言基础
后续代码看不懂了再看这。
1.结构体
struct tag //tag结构体标签
{
member-list //成员变量定义
}variable-list;//结构变量
2.typedef
作用给类型取新名字
typedef int SLDataType;//SLDataType是int的新名字
3.typedef与结构体
typedeftypedef struct SeqList
{
size_t size;
}SeqList;//这行}之前的就是结构体的类型
//SeqList是这个结构体的新名字
注意:SeqList不是结构变量,要区分。
4.realloc
void *realloc(void *ptr, size_t size)
ptr–指针指向一个要重新分配内存的内存块
size–内存块的新大小。注意:大小应该是本来的大小加上想要的扩大的大小,比如本来40个字节的大小,需要新的40个字节的大小,那么size应该是80个字节。
5.free
void free(void *ptr)
C 库函数 void free(void *ptr) 释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。
ptr–指针指向一个要释放内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果传递的参数是一个空指针,则不会执行任何动作。
每次开辟空间需要记得释放。
注意:free不能部分释放,只能释放全部
6.柔性数组
博客地址(现在还没写):
1.顺序表的概念
顺序表是用一段物理地址连续存储单元依次存储数据元素的线性结构
一般情况下采用数组存储。在数组上完成数据的增删查改。
2.顺序表的结构
顺序表可以分为静态顺序表与动态顺序表。
1.静态顺序表:使用定长数组存储元素。
#define N 7
typedef int SLDataType;
typedef struct SeqList
{
SLDataType array[N];//定长数组,存储数据
size_t size;//有效数据的长度
}SeqList;
2.动态顺序表:使用动态开辟的数组存储
typedef struct SeqList
{
SLDataType* arry;//指向动态开辟的数组
size_t size;//有效数据的个数
size_t capacity;//容量空间的大小
}SeqList;
3.顺序表接口
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们使用动态顺序表。
typedef int SLDataType;
//顺序表的动态存储
typedef struct SeqList
{
SLDateType* array;//指向动态开辟的数组
size_t size;//有效数据个数
size_t capacity;//容量空间的大小
}SeqList;
//基本增删查改接口
//顺序表初始化
//1.顺序表初始化
void SeqListInit(SeqList* psl);
//2.检查空间,如果满了,进行增容
void SeqListCheckCapacity(SeqList* psl);
//3.顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
//4.顺序表尾删
void SeqListPopBack(SeqList* psl);
//5.顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x);
//6.顺序表头删
void SeqListPopFront(SeqList* psl);
//7.顺序表查找
int SeqListFind(SeqList* psl, SLDataType x);
//8.顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);
//9.顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);
//10.顺序表销毁
void SeqListDestory(SeqList* psl);
//11.顺序表打印
void SeqListPrint(SeqList* psl);
4.顺序表接口的实现
1.顺序表的初始化
void SeqListInit(SeqList* psl)
{
assert(psl);
psl->a = NULL;
psl->size = 0;
psl->capacity = 0;
}
2.检查空间,如果空间满了,进行增容
void SeqListCheckCapacity(SeqList* psl)
{
assert(psl);
if (psl->size == psl->capacity)
{
int newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
SLDataType* tmp = realloc(psl->a, newCapacity* sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
psl->a = tmp;
psl->capacity = newCapacity;
}
}
3.顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x)
{
assert(psl);
SeqListCheckCapacity(psl);
psl->a[psl->size] = x;
psl->size++;
}
4.顺序表尾删
void SeqListPopBack(SeqList* psl)
{
assert(psl);
if (psl->size == 0)
{
return;
}
psl->size--;
}
5.顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x)
{
assert(psl);
SeqListCheckCapacity(psl);
//挪动数据
int end = psl->size - 1;
while (end >= 0)
{
psl->a[end + 1] = psl->a[end];
--end;
}
psl->a[0] = x;
psl->size++;
}
6.顺序表头删
void SeqListPopFront(SeqList* psl)
{
assert(psl);
int left=0;
while (left<psl->size-1)
{
psl->a[left] = psl->a[left + 1];
++left;
}
psl->size--;
}
7.顺序表查找
int SeqListFind(SeqList* psl, SLDataType x)
{
assert(psl);
for (int i = 0; i < psl->size; i++)
{
if (psl->a[i] == x)
return i;
}
return -1;
}
8.顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
{
assert(psl);
pos=pos - 1;
if (pos > psl->size || pos < 0)
{
return;
}
SeqListCheckCapacity(psl);
int first = psl->a[pos];
for (int i = psl->size - 1; i >=(int )pos; --i)
{
psl->a[i + 1] = psl->a[i];
}
psl->size++;
psl->a[pos] = x;
}
9.顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos)
{
assert(psl);
if (pos > psl->size || pos < 0)
{
return;
}
pos = pos - 1;
int left = pos;
while (left < psl->size - 1)
{
psl->a[left] = psl->a[left + 1];
++left;
}
psl->size--;
}
10.顺序表销毁
void SeqListDestory(SeqList* psl)
{
assert(psl);
free(psl->a);
psl->a = NULL;
psl->capacity = psl->size = 0;
}
11.顺序表打印
void SeqListPrint(SeqList* psl)
{
assert(psl);
for (int i = 0; i < psl->size; i++)
{
printf("%d ",psl->a[i]);
}
printf("\n");
}
5.顺序表接口实现的一些问题
以后遇到新的再添加。
1.顺序表数据满了以后,一定是扩容2倍吗?
答:不一定,1.5倍也可以,但是2倍比较合适。
每次扩容新空间不能太大,也不能太小,太大容易造成空间浪费,太小则会导致频繁扩容而影响程序效率。
2.在 接口8.顺序表在pos位置插入x 中,为什么for循环中pos需要强制类型转换?
答:如果不强制类型转换,那么如果插入的位置是0将会进入死循环,所以只能写成i>pos,i==pos的部分需要自己另外判断。
为什么会死循环呢?因为这里运行的时候发生了隐式类型转换导致i<0的时候依旧进行循环。
6.数组相关面试题
第一题
第二题
Loading Question… - 力扣(LeetCode)
第三题