大家好今天是我第一次分享博客,主要是想对自己有一个监督作用,如果同时能够帮助到大家的话就更好了
用C语言写线性表(动态分配内存) (verison 0.0.1)
里面有初始化,新增元素,删除元素,查询元素,修改元素,根据位置插入元素,输出线性表,检查内存是否足够,销毁线性表等功能
- 定义存储元素节点(就是你要存储什么内容)
typedef struct ElemType {
int val;
char val2;
} ElemType;
- 定义线性表
struct SqList {
struct ElemType *firstElemType; //存储数据首地址
int length; //顺序表当前长度大小
int listSize; //顺序表内存大小
};
- 初始化函数
void InitList(struct SqList *L) {
//先分配内存
L->firstElemType = (ElemType *) malloc(LIST_INIT_SIZE * sizeof(ElemType));
if (!L->firstElemType) {
printf("内存分配失败");
exit(0);
}
L->length = 0;
L->listSize = LIST_INIT_SIZE;
printf("初始化完成\n");
}
解释:由主函数中声明的线性表L传入到此函数中会进行初始化,主要是给线性表分配内存,同时将里面的当前长度length初始化赋值为0,将第一次分配的总内存设置为提前定义好的 LIST_INIT_SIZE数值。
- 检查内存是否足够函数
struct SqList *Check(struct SqList *L) {
//检查顺序表内存大小
if (L->length >= L->listSize) {
printf("\n--------内存不足-------\n");
ElemType *newElemType;
//扩大新内存
newElemType = (ElemType *) realloc(L->firstElemType, (L->length + LIST_INCREMENT) * sizeof(ElemType));
if (!newElemType) {
printf("新增内存分配失败");
exit(0);
}
//重新指定新地址
L->firstElemType = newElemType;
L->listSize = L->length + LIST_INCREMENT;
return L;
} else {
return L;
}
}
因为后面部分操作在执行前要进行内存大小的检查,所以我就把这部分代码封装到了一个单独的函数当中。传入线性表L后会对L进行检查如果内存足够就直接返回,如果内存不足够就用realloc函数进行扩容然后重新指定线性表中数组的首地址和最大容量的大小,然后再返回。
- 增加元素操作(单次只能增加一个)
void AddList(struct SqList *L, struct ElemType e) {
L = Check(L);
L->firstElemType[L->length] = e;
L->length++;
}
解释:首先同意上面封装的Check函数进行内存判断,然后将要增加的元素直接放入数组中
- 根据元素位置(不是下标)插入数据
void InsertList(struct SqList *L, int i, struct ElemType e) {
//检查i的合法性
if (i < 1 || i > L->length) {
if (i == L->length + 1) {
//如果i等于length+1说明想插入的是最有一个位置,直接新增元素就好了
AddList(L, e);
//插入成功后就直接返回,否则这里新增后下面就可以再次插入了导致数据重复
return;
} else {
return;
}
}
//检查内存是否足够
L = Check(L);
//开始插入数据
//先找到插入位置
ElemType *q;
q = &(L->firstElemType[i - 1]);
//将后面的所有数据全部后移一位
for (ElemType *p = &(L->firstElemType[L->length - 1]); p >= q; p--) {
*(p + 1) = *p; //这里的*号是取内容
//上面是+1而不是+1*sizeof(ElemType)是因为,真实的物理地址是相差sizeof(ElemType)的,而&取到的是虚拟地址
//真实的物理地址是由操作系统负责取不到的
}
*q = e;
L->length++;
printf("插入成功");
}
解释:进行必要的检查之后,先用一个临时变量q暂时存储要插入位置的元素,然后将这个元素后的所有元素全部往后移一位,然后将这个位置替换为要替换的那个元素
- 更新元素函数
//替换元素
void UpdateList(struct SqList *L, int i, struct ElemType e) {
for (int i = 0; i < L->length; i++) {
L->firstElemType[i] = e;
}
printf("替换/修改完成");
}
- 删除元素函数
//删除元素
void DeleteList(struct SqList *L, int i) {
//检查i是否合理
if (i < 1 || i - 1 > L->length) {
return;
}
ElemType *q;
q = &(L->firstElemType[i - 1]);
for (ElemType *p = q; p < &(L->firstElemType[L->length - 1]); p++) {
*(p) = *(p + 1); //取内容往前覆盖
}
L->length--;
printf("删除成功");
}
- 查询元素函数
//查询元素(返回下标)
int FindElem(struct SqList *L, struct ElemType e) {
for (int i = 0; i < L->length; i++) {
if (L->firstElemType[i].val == e.val && L->firstElemType[i].val2 == e.val2) {
return i;
}
}
return -1;
}
- 输出线性表函数
//输出函数
void MyPrintf(struct SqList *L) {
printf("该顺序表一共有%d个节点\n", L->length);
for (int i = 0; i < L->length; i++) {
printf("第%d个节点元素的第一个属性值为%d\t第二个属性值为%c\n", i + 1, L->firstElemType[i].val,
L->firstElemType[i].val2);
}
}
- 销毁线性表函数
void ListDestroy(struct SqList *L) {
free(L->firstElemType);
L->length = 0;
L->listSize = 0;
printf("\n销毁成功");
}
我这个是很久之前写的代码,然后这个解释什么的也不是很完善,但是我后面不定时进行修改和优化的。
谢谢查阅🙏