赞
踩
目录
顺序存储结构——借助元素在存储器中的相对位置来表示
数据元素间的逻辑关系:(逻辑相邻,物理相邻)
顺序表是以数组形式保存的线性表,使用一段连续的存储空间来存储元素,使得元素在内存中的位置是相邻的,可以通过索引快速访问到特定位置的元素(随机访问效率高)。
由于顺序表是连续的,所以在添加和删除元素时需要移动后面的元素,增删效率慢。
建议在开头包含头文件 #include<assert.h>
并在有接收指针的函数体内内使用 assert(指针变量); 来保证传递过来的指针的不为空指针。
- #include<stdio.h>
- #include<stdlib.h>
- #define INIT_CAPACITY 3 //初始默认的容量
-
- typedef struct SqList
- {
- int* data; //指向顺序表,存储元素
- int size; //顺序表的大小/元素个数
- int capacity; //顺序表的容量
- }SqList;
这里定义的结构体中有2个元素:
- elem是一个int*类型的指针,这个指针在初始化后会指向一块空间,就是我们需要的顺序表,用于顺序表存储数据(你可以把其看做一个数组);
- length是用于记录顺序表的长度(不是代表元素的个数)
补充:如果你使用的是Visual Studio进行编写的代码,请在第一行添加:
#define _CRT_SECURE_NO_WARNINGS
- int Init_SqList(SqList* L)
- {
- //给顺序表开辟大小为默认容量的空间
- int* p = (int*)malloc(sizeof(int) * INIT_CAPACITY);
- if (p)//判断p是否为空指针
- {
- L->data = p;
- L->size = 0;
- L->capacity = INIT_CAPACITY;
- return 0;
- }
- else
- return 1;
- }
main函数中调用初始化函数:
//定义一个结构体变量L SqList L; //初始化结构体内容 int flag = Init_SqList(&L); if (!flag) printf(">顺序表初始化成功\n"); else printf(">顺序表初始化失败\n");
- calloc函数向内存申请一块连续可用的空间,并且把空间中每一个字节都初始化为0。
·Q:为什么要进行强制转换?
·A:calloc函数成功开辟空间后会返回指向这块空间的指针(类型为void*),而顺序表的元素类型是int,指向顺序表的指针需要的指针类型int*,所以需要把指向已开辟空间的指针的类型强制转换为顺序表存储的数据对应类型再赋值给顺序表。
补充:顺序表在内存中的存储是连续的,顺序表的元素类型是int,一个int占4个字节,而使用int*类型的指针,可以在访问数据时一次性访问4个字节,刚好对应索引,每次刚好能访问一个元素。
·Q:开辟空间后为什么要进行判断?
·A:calloc函数成功开辟空间后会返回指向这块空间的指针,而开辟失败则会返回一个空指针NULL,空指针无法进行操作,所以此时进行判断可以确保程序在分配内存失败时不会继续使用无效的指针,从而避免可能导致程序崩溃或产生未定义行为的问题。
- void Insert_In_Head(SqList* L, int e)
- {
- if (L->size == 0)
- {
- L->data[0] = e;
- (L->size)++;
- }
- else
- {
- int end = L->size;
- while (end > 0)
- {
- L->data[end] = L->data[end-1];
- end--;
- }
- L->data[0] = e;
- (L->size)++;
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
先判断顺序表是否为空,如果顺序表内没有元素则直接将新元素插入到[0]索引处;如果顺序表内有元素则需要将插入点及插入点后的元素进行后移,然后再把新元素进行插入。
由于在尾部插入元素可以直接将元素插入,不需要考虑元素的后移,所以只需要在“头插法”的基础上进行改写即可。
在顺序表L中第 i 个位置插入数据元素 e,插入点之后的所有元素需要一起向后移动。
为了代码容易理解,第 n 个位置代表的是顺序表中索引为 n-1 。(第1个位置就是索引0)
- void Insert_SqList(SqList* L, int n, int e)//位置n对应索引n-1
- {
- Check_Capacity(L); //检查并决定是否需要扩容
- if (n < 1 || n > L->capacity )
- {
- printf("元素插入位置%d不合法!\n", n);
- return 1;
- }
- //将插入的位置点之后的元素后移
- if (n <= L->size)
- {
- int i = 0;
- for (i = L->size; i >= n-1; i--)
- {
- L->data[i + 1] = L->data[i];
- }
- }
- L->data[n-1] = e;
- (L->size)++;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
分析:
在执行插入功能前:我们需要先调用Check_Capacity函数来判断顺序表中的元素个数是否已经达到了设定的容量大小,并决定是否执行顺序表的扩容。
void Check_Capacity(SqList* L) { //若顺序表元素个数已经等于此时最大容量时则进行扩容 if (L->size == L->capacity) { int* p = (int*)realloc(L->data, sizeof(int)*(L->size + 10)); //对L->data指向的空间增加为大小为sizeof(int)*(L->size + 10)的空间,赋值给指针p if (p) { //若指针p不为空则代表空间扩容成功,把空间地址再赋值给L->data L->data = p; //实时更新顺序表容量的大小 L->capacity = L->capacity + 10; printf(">>>size:%d->顺序表已扩容\n",L->size); } else printf(">>>顺序表扩容失败\n"); } } /* 对于relloc函数的用法这里不再赘述. */接下来则想要判断要插入元素的位置是否合理,插入的位置越界则提示并结束函数。
在确保了代码的健壮性后,开始插入元素。当插入位置不是最后一个元素的下一个,则需要空出需要插入的位置,将插入位置的元素及后面的元素进行后移,最后将新元素插入。
- int Delect_SqList(SqList* L, int n)
- {
- if (L->size == 0)
- {
- printf(">>>顺序表为空表\n");
- return 1;
- }
- if (n < 1 || n > L->size)
- {
- printf(">>>删除位置无元素\n");
- return 1;
- }
- int i = 0;
- int e = L->data[n - 1]; //记录删除的元素
- for (i = n-1; i < L->size; i++)
- {
- L->data[i] = L->data[i + 1];
- }
- printf(">>>已删除索引为%d的元素%d.\n", n - 1, e);
- (L->size)--;
- return 0;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
在顺序表L中删除位置n的元素(即索引为n-1的元素),先判断顺序表是否为空和要删除的位置是否越界。然后依次从第n个位置开始,将第n+1个位置的数据赋值给第n个位置,后面的元素依次前移,指定位置的元素被覆盖,即可完成指定位置元素的删除。
- void Destroy_SqList(SqList* L)
- {
- L->size = 0;
- L->capacity = 0;
- free(L->data);//释放空间
- L->data = NULL;
- printf(">>>顺序表已销毁\n");
- }
将基础数据类型的变量赋值为0,然后释放data指针指向的空间内存并将L->data指针赋值为空指针,防止野指针的产生。
传递顺序表和需要查找的元素e,找到元素返回元素的索引,找不到返回-1
- int Locate_Elem(SqList* L, int e)
- {
- if (L->size == 0)
- return 1;
- int i = 0;
- for (i = 0; i < L->size; i++)
- {
- if (L->data[i] == e)
- {
- printf(">元素%d所在的索引为: %d\n", e, i);
- return i;
- }
- }
- printf(">查找失败, 顺序表中没有此元素.\n");
- return -1;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- void Print_SqList(SqList* L)
- {
- if (L->size == 0)
- return;
- printf("-----打印顺序表中元素----- \n");
- for (int i = 0; i < L->size; i++)
- {
- printf("[%d]: %d, ", i, L->data[i]);
- }
- printf("\n--------------------------\n");
-
- }
头文件 head.h
#pragma once #include<stdio.h> #include<stdlib.h> #define INIT_CAPACITY 5 //初始的容量 typedef struct SqList { int* data; //指向顺序表,存储元素 int size; //顺序表的大小/元素个数 int capacity; //顺序表的容量 }SqList; //初始化顺序表 int Init_SqList(SqList* L); //指定位置插入元素 void Insert_SqList(SqList* L, int i, int e); //在头部添加元素 void Insert_In_Head(SqList* L, int e); //打印顺序表中元素 void Print_SqList(SqList* L); //检查顺序表大小并决定是否扩容 void Check_Capacity(SqList* L); //删除指定元素 int Delect_SqList(SqList* L, int n); //按值查找 int Locate_Elem(SqList* L, int e); //销毁顺序表 void Destroy_SqList(SqList* L);
源文件 顺序表.c
#include "head.h" int main() { //定义一个结构体变量L SqList L; //初始化结构体内容 int flag = Init_SqList(&L); if (!flag) printf(">顺序表初始化成功\n"); else printf(">顺序表初始化失败\n"); //指定位置插入元素 Insert_SqList(&L, 1, 1); Insert_SqList(&L, 2, 2); Insert_SqList(&L, 3, 3); Insert_SqList(&L, 4, 4); //在头部添加元素 Insert_In_Head(&L, 6); //删除指定元素 Delect_SqList(&L, 2); //按值查找 Locate_Elem(&L, 4); //打印顺序表中元素 Print_SqList(&L); //销毁顺序表 Destroy_SqList(&L); return 0; } int Init_SqList(SqList* L) { //给顺序表开辟大小为默认容量的空间 int* p = (int*)malloc(sizeof(int) * INIT_CAPACITY); if (p)//判断p是否为空指针 { L->data = p; L->size = 0; L->capacity = INIT_CAPACITY; return 0; } else return 1; } void Insert_SqList(SqList* L, int n, int e)//位置n对应索引n-1 { Check_Capacity(L);//检查顺序表大小并决定是否扩容 if (n < 1 || n > L->capacity ) { printf("元素插入位置%d不合法!\n", n); return 1; } //将插入的位置点之后的元素后移 if (n <= L->size) { int i = 0; for (i = L->size; i >= n-1; i--) { L->data[i + 1] = L->data[i]; } } L->data[n-1] = e; (L->size)++; } void Check_Capacity(SqList* L) { //若顺序表元素个数=最大容量时则进行扩容 if (L->size == L->capacity) { int* p = (int*)realloc(L->data, sizeof(int)*(L->size + 10)); if (p) { L->data = p; L->capacity = L->capacity + 10; printf(">>>size:%d->顺序表已扩容\n",L->size); } else printf(">>>顺序表扩容失败\n"); } } void Print_SqList(SqList* L) { if (L->size == 0) return; printf("-----打印顺序表中元素----- \n"); for (int i = 0; i < L->size; i++) { printf("[%d]: %d, ", i, L->data[i]); } printf("\n--------------------------\n"); } int Delect_SqList(SqList* L, int n) { if (L->size == 0) { printf(">>>顺序表为空表\n"); return 1; } if (n < 1 || n > L->size) { printf(">>>删除位置无元素\n"); return 1; } int i = 0; int e = L->data[n - 1]; //记录删除的元素 for (i = n-1; i < L->size; i++) { L->data[i] = L->data[i + 1]; } printf(">>>已删除索引为%d的元素%d.\n", n - 1, e); (L->size)--; return 0; } void Insert_In_Head(SqList* L, int e) { if (L->size == 0) { L->data[0] = e; (L->size)++; } else { int end = L->size; while (end > 0) { L->data[end] = L->data[end-1]; end--; } L->data[0] = e; (L->size)++; } } int Locate_Elem(SqList* L, int e) { if (L->size == 0) return 1; int i = 0; for (i = 0; i < L->size; i++) { if (L->data[i] == e) { printf(">元素%d所在的索引为: %d\n", e, i); return i; } } printf(">查找失败, 顺序表中没有此元素.\n"); return -1; } void Destroy_SqList(SqList* L) { L->size = 0; L->capacity = 0; free(L->data);//释放空间 L->data = NULL; printf(">>>顺序表已销毁\n"); }
运行结果:
希望我的作品能够带给你一些启发。我的下一篇博客:
链表入门:“单链表“的基本操作详解(C语言)https://blog.csdn.net/Mzyh_c/article/details/133841591?spm=1001.2014.3001.5501
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。