由于疫情->->学校又封禁了----开始上网课 ,在宿舍里学习哈哈哈 ------今天敲代码了吗?
顺序表
1)顺序表是用一段物理地址连续的存储单元一次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成增删查改
顺序表:可动态增长的数组,要求数据是连续存储的
2)顺序表的定义
1、静态的顺序表
缺点:给小了可能不够用,给大了造成浪费;非常不实用
#define N 10
typedef int SecLdatatype;
typedef struct SeqList
{
SecLdatatype a[N];
size_t size;
}SeqList;
2、动态增长的顺序表
使用动态开辟的数组来存储元素
动态顺序表可以根据需要来分配空间大小
size表示当前顺序表中存储的个数
capacity表示当前空间的内存大小
typedef int SecLdatatype;
typedef struct SecList
{
SecLdatatype* a;//指向动态开辟的数组
int size ;//有效数据个数
int capacity ;//容量
}SL;
2)顺序表的接口
函数的声明(SecList.h)
#pragma once//防止文件重复包含
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//初始化结构体
void InitSecList(SL*pc);
//释放掉动态开辟的内存
void DestorySecList(SL* pc);
//尾插
void PushBack(SL* pc, SecLdatatype x);
//打印顺序表
void PrintSecList(SL* pc);
//尾删
void PopBack(SL* pc);
//头插
void PushFront(SL* pc, SecLdatatype x);
//头删
void PopFront(SL* pc);
//查找
int Findx(SL* pc, SecLdatatype x);
//在pos的位置插入
void SecLInsert(SL* pc, int pos, SecLdatatype x);
//将pos删除
void SecEarse(SL* pc, int pos);
函数的实现
1.首先 先决条件要思考;要将顺序表的内容初始化 给数组开辟一定空间,将size置0和将capacity置成和动态开辟数组内存相符合的数;
2.在结束后要记得释放动态开辟的内存,防止内存泄露
3.检查内存
void InitSecList(SL* pc)
{
assert(pc);
pc->a = (SecLdatatype*)malloc(sizeof(SecLdatatype)*4);
if (pc->a == NULL)
{
perror("malloc fail");//如果动态开辟失败就退出
exit(-1);
}
pc->size = 0;
pc->capacity = 4;
}
void DestorySecList(SL* pc)
{
assert(pc);
free(pc->a);//只有a的内存是动态开辟
pc->a = NULL;//将a置空,也可以不置空,因为形参的改变不会影响实参;
pc->size = pc->capacity = 0;
}
//检查内存 防止溢出 当size==capacity时代表着内存已经满了
//此时就需要动态开辟一定的内存
check_capacity(SL* pc)
{
assert(pc);
if (pc->capacity == pc->size)
{
int newcapacity = pc->capacity * 2;//再扩容4个
SecLdatatype* tmp = (SecLdatatype*)realloc(pc->a, pc->capacity*2*sizeof(SecLdatatype));//newcapacity*int;
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
pc->a = tmp;
pc->capacity = newcapacity;
}
}
尾插
//尾插 首先要检查内存 然后将x插在后面
void PushBack(SL* pc, SecLdatatype x)
{
assert(pc);
check_capacity(pc);
pc->a[pc->size] = x;
pc->size++;//有效数字+1;
}
分成一组一组测试
void Test1()
{
SL sl;
InitSecList(&sl);
PushBack(&sl, 1);
PushBack(&sl, 2);
PushBack(&sl, 3);
PushBack(&sl, 4);
PushBack(&sl, 5);
PrintSecList(&sl);
DestorySecList(&sl);
}
int main()
{
Test1();
return 0;
}
调试结果
尾删
//尾删
void PopBack(SL* pc)
{
assert(pc);
pc->size--;
//也可以不置0 因为有可能 原来的位置上就是0;
pc->a[pc->size] = 0;
}
头插
void PushFront(SL* pc, SecLdatatype x)
{
assert(pc);
check_capacity(pc);
//数字需要一个一个往后挪
//size记录数据时是从1开始
//所以重新定义一个数据为end来记录有效数据的下标(从0开始)
int end = pc->size - 1;
while (end>=0)
{
pc->a[end +1] = pc->a[end];
end--;
}
//空出pc->a[0]将x赋值上去
pc->a[0] = x;
pc->size++;
}
要提一嘴 就是这个循环结束条件要挨个挨个往后挪一个
举个例子 (如图)条件就是将下标为0位置上的挪到下标为1的位置上
就需要重新定义一个变量end 做下标位置 从后往前挪
当end==0时结束循环;
调试
void Test3()
{
SL sl;
InitSecList(&sl);
PushFront(&sl, 1);
PushFront(&sl, 2);
PushFront(&sl, 3);
PushFront(&sl, 4);
PushFront(&sl, 5);
PrintSecList(&sl);
DestorySecList(&sl);
}
int main()
{
Test3();
return 0;
}
调试结果
头删
void PopFront(SL* pc)
{
assert(pc);
int begin = 1;
int end = pc->size ;
//将头删掉 再将后面的数据往后挪
while (begin < end)
{
pc->a[begin-1] = pc->a[begin];
begin++;
}
pc->size--;
}
em跟头插一样 强调一下 这个得从前往后挪 举个例子
定义一个begin=1然后一个一个挪 从前往后挪
当begin==size时结束循环
为空时不能再删(很危险)
调试
void Test3()
{
SL sl;
InitSecList(&sl);
PushFront(&sl, 1);
PushFront(&sl, 2);
PushFront(&sl, 3);
PushFront(&sl, 4);
PushFront(&sl, 5);
PopBack(&sl);
PopBack(&sl);
PopBack(&sl);
PrintSecList(&sl);
DestorySecList(&sl);
}
int main()
{
Test3();
return 0;
}
调试结果
查找函数
int Findx(SL* pc,SecLdatatype x)
{
assert(pc);
int i = 0;
for (i = 0; i < pc->size; i++)
{
//找到就返回下标
if (pc->a[i] == x)
{
return i;
}
}
return NULL;
}
找不到就返回空
调试
void Test3()
{
SL sl;
InitSecList(&sl);
PushFront(&sl, 1);
PushFront(&sl, 2);
PushFront(&sl, 3);
PushFront(&sl, 4);
PushFront(&sl, 5);
PrintSecList(&sl);
int ret = Findx(&sl, 3);
if (ret)
{
printf("找到了\n");
}
else
{
printf("找不到");
}
PrintSecList(&sl);
DestorySecList(&sl);
}
int main()
{
Test3();
return 0;
}
调试结果
在指定位置上添加
void SecLInsert(SL* pc, int pos, SecLdatatype x)
{
assert(pc);
assert(pos >= 0);//pos必须是大于0的
assert(pos <= pc->size);//要对顺序表进行操作pos的位置只能在size内
check_capacity(pc);
int end = pc->size - 1;
while (end>=pos)
{
//先将数据往后挪 空出pos的位置
pc->a[end + 1] = pc->a[end];
end--;
}
//再将x放到pos的位置上
pc->a[pos] = x;
pc->size++;
}
此时 需要用到刚才所查找的函数 找到的下标位置处 然后对这个位置进行添加或者修改
要注意的时 将pos处的内容往后挪一个 正如刚刚的尾插;不同的是这次终止的位置时pos
将pos处的数据挪走以后就可以终止循环
调试
void Test2()
{
SL sl;
InitSecList(&sl);
PushBack(&sl, 1);
PushBack(&sl, 2);
PushBack(&sl, 3);
PushBack(&sl, 4);
PushBack(&sl, 5);
int ret = Findx(&sl, 2);
SecLInsert(&sl, ret, 20);
PrintSecList(&sl);
DestorySecList(&sl);
}
int main()
{
Test2();
return 0;
}
调试结果
将指定位置的数据删除;
//删除pos位置
void SecEarse(SL* pc, int pos)
{
assert(pos>=0);
assert(pc);
assert(pos <= pc->size);
int begin = pos+1;
while (begin <= pc->size)
{
//将pos往后的位置挪到前去
pc->a[begin-1] = pc->a[begin];
begin++;
}
pc->size--;
}
调试
void Test2()
{
SL sl;
InitSecList(&sl);
PushBack(&sl, 1);
PushBack(&sl, 2);
PushBack(&sl, 3);
PushBack(&sl, 4);
PushBack(&sl, 5);
int ret = Findx(&sl, 2);
SecEarse(&sl, ret);
PrintSecList(&sl);
DestorySecList(&sl);
}
int main()
{
Test2();
return 0;
}