前言:
数据结构无论是以后就业还是考研,对于计算机方向的同学来说都是必修的一门课,所以,深入理解各种数据结构是一名合格程序员的基本素养。这里我就先带大家了解最简单的数据结构--顺序表吧。
1.什么是顺序表
顺序表是一种线性数据结构,而且其存储数据的空间是连续的,这一点跟数组非常像。
由于其基本结构式是连续的,我们在查找元素时也就可以用下标映射快速定位到元素的位置,是编写常见算法的常用数据结构之一。
2.顺序表的功能
顺序表的主要操作包括访问、插入、删除和修改等。其中,访问是顺序表最基本的操作之一,可以通过下标(索引)来访问顺序表中的元素,时间复杂度为 O(1)。插入和删除操作都涉及到元素的移动,因此它们的时间复杂度为 O(n)。修改操作和访问类似,时间复杂度也为 O(1)。
3.c语言代码模拟实现顺序表
主要思路就是:首先是定义数据类型(我这里是int),然后是定义结构体SeqList(顺序表),这个结构体用一个date指针来指向数据区域(我这里是用malloc动态开辟内存),size表示目前顺序表中的元素,cap表示目前顺序表的容量。
在实现顺序表的增删查改过程中,要注意size的变化,看是否已经达到最大容量,根据实际情况选择扩容(用realloc)。
3.1 SeqList.h头文件
用来声明各种功能函数,定义数据类型等。
代码:
#define _CRT_SECURE_NO_WARNINGS 1
//SeqList.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define INIT_SIZE 4
#define INIT_CAP 10
typedef int SLDateType;
typedef struct SeqList {
SLDateType* date;
int size;
int cap;
}SeqList;
void SeqListInit(SeqList* SL);
//顺序表销毁
void SeqListDestroy(SeqList* SL);
//打印顺序表
void PrintSeqList(SeqList* SL);
//尾插元素
void SeqListPushBack(SeqList* SL, int x);
//头插元素
void SeqListPushFront(SeqList* SL, int x);
//指定位置插入元素
void SeqListInsert(SeqList* SL, int pos, int x);
// 表尾弹出元素
void SeqListPopBack(SeqList* SL);
//表头弹出元素
void SeqListPopFront(SeqList* SL);
//删除指定位置
void SeqListErase(SeqList* SL, int pos);
//查找元素
int SeqListFind(SeqList* SL, int x);
3.2 SeqList.c源文件
实现各种功能函数。
代码:
#define _CRT_SECURE_NO_WARNINGS 1
//SeqList.c
#include"SeqList.h"
//顺序表初始化
void SeqListInit(SeqList* SL) {
SL->date = (SLDateType*)malloc(sizeof(SLDateType) * INIT_CAP);
SL->size = 0;
SL->cap = INIT_CAP;
}
//顺序表销毁
void SeqListDestroy(SeqList* SL) {
assert(SL);
free(SL->date);
SL->size = 0;
SL->cap = 0;
}
//检查顺序表是否已满,如果满了就扩容
static void CheckSLIsMax(SeqList* SL) {
assert(SL);
if (SL->size == SL->cap) {
SeqList* res = SL;
res = (SeqList*)realloc(SL->date, sizeof(SLDateType) * ((SL->cap) * 2));
if (res == NULL) {
perror("realloc:fail");
}
SL->date = res;
(SL->cap) *= 2;
return;
}
return;
}
//打印顺序表
void PrintSeqList(SeqList* SL) {
assert(SL);
for (int i = 0; i < SL->size; i++) {
printf("%d ", SL->date[i]);
}
printf("\n");
printf("该顺序表目前有%d个数据,容量为%d\n", SL->size, SL->cap);
printf("\n");
return;
}
//尾插元素
void SeqListPushBack(SeqList* SL, int x) {
assert(SL);
CheckSLIsMax(SL);
SL->date[SL->size] = x;
SL->size++;
}
//头插元素
void SeqListPushFront(SeqList* SL,int x) {
assert(SL);
CheckSLIsMax(SL);
for (int i = SL->size; i >=1; i--) {
SL->date[i] = SL->date[i - 1];
}
SL->date[0] = x;
SL->size++;
return;
}
//插入元素到指定位置
void SeqListInsert(SeqList* SL, int pos, int x) {
assert(SL);
if (pos >= 0 && pos < SL->size) {
CheckSLIsMax(SL);
for (int i = SL->size; i >= pos+1; i--) {
SL->date[i] = SL->date[i - 1];
}
SL->date[pos] = x;
SL->size++;
}
else {
perror("插入位置有误");
}
}
// 表尾弹出元素
void SeqListPopBack(SeqList* SL) {
assert(SL);
if (SL->size > 0) {
//SL->date[SL->size - 1];
SL->size--;
}
else {
perror("SeqListPopBack: failen");
}
return;
}
//表头弹出元素
void SeqListPopFront(SeqList* SL) {
assert(SL);
if (SL->size > 0) {
for (int i = 0; i < SL->size-1; i++) {
SL->date[i] = SL->date[i + 1];
}
SL->size--;
}
else {
perror("SeqListPopFront: faile");
}
return;
}
//删除指定位置
void SeqListErase(SeqList* SL, int pos) {
assert(SL);
if (pos >= 0 && pos < SL->size) {
for (int i = pos; i < SL->size-1; i++) {
SL->date[i] = SL->date[i + 1];
}
SL->size--;
}
else {
perror("SeqListErase:fail");
}
}
//查找元素
int SeqListFind(SeqList* SL, int x) {
assert(SL);
for (int i = 0; i < SL->size; i++) {
if (SL->date[i] == x) {
return i;
}
}
return -1;
}
3.3test.c
用来存放main()函数,测试各种数据,我这里就简单给出一组测试数据(懒)
代码:
SeqList SL;
void test1() {
SeqListInit(&SL);
SeqListPushBack(&SL, 1);
SeqListPushBack(&SL, 2);
SeqListPushBack(&SL, 3);
SeqListPushBack(&SL, 4);
SeqListPushBack(&SL, 5);
SeqListPushBack(&SL, 6);
PrintSeqList(&SL);
SeqListPushFront(&SL, 4);
PrintSeqList(&SL);
}
int main() {
test1();
return 0;
}
4.总结
学数据结构一般都是从顺序表开始的,顺序表虽然简单,但是是我们经常使用的一种数据结构,了解并学会顺序表功能的具体实现对以后学习高级数据结构打下基础。总之,对于简单的知识我们要不能轻视,反而要更加重视对于基础的巩固,万丈高楼平地起嘛!