前言
介绍顺序表之前先介绍一下线性表,线性表是一种常见的数据结构,它是最基本的线性数据结构之一。线性表中的数据元素之间存在一对一的线性关系,即每个元素(除了第一个和最后一个)都有一个直接前驱和一个直接后继。线性表是一个有限序列,包含0个或多个数据元素,线性表中的所有数据元素具有相同的数据类型。线性表一般有2种存储方式,一种是顺序存储,另一种是链式存储。而顺序表便是线性表顺序存储方式的体现。
基本概念
顺序表是一种线性表的存储方式,其中数据元素按照逻辑顺序依次存储在内存中的一块连续空间内。每个数据元素在内存中的位置可以通过其索引(或下标)快速计算得到。
特点
-
存储结构:顺序表是基于数组实现的,数据元素在内存中连续存放。
-
随机访问:可以通过索引快速访问任意位置的元素,时间复杂度为 O(1)。
-
插入和删除操作效率低:插入或删除元素时,通常需要移动大量元素以保持存储空间的连续性,时间复杂度为 O(n),其中 n 是表的长度。
-
空间利用率:顺序表需要预先分配存储空间,可能会导致空间浪费(分配过大)或存储空间不足(分配过小)。
初始化顺序表
首先定义顺序表结构体,然后定义初始化函数,申请空间并初始化数组和长度,之后返回指向该顺序表的指针。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 10 //顺序表中最大元素个数
typedef struct
{
int data[MAX_LEN];//存储数据元素
int len;//当前顺序表长度
}sqlist_t;
static sqlist_t* sqlist_init()
{
sqlist_t* sq = (sqlist_t*)malloc(sizeof(sqlist_t));//申请空间
if (sq != NULL)
{
memset(sq->data, 0, MAX_LEN);
sq->len = 0;
return sq;//初始化数组和长度后返回顺序表指针
}
}
int main()
{
sqlist_t* s = sqlist_init();
return 0;
}
增加元素
增加元素即插入元素,这一步实现插入函数。顺序表不限制插入元素的位置,可以用一个形参来指定插入的位置。
顺序表在进行插入时需要大量移动元素。比如:如果原先顺序表里是1,2,3,4,此时想在2,3之间插入5,那么就需要将3,4各往后移动一个位置,此时就空了一个位置出来,再把5放进去。
/*
插入函数,sq为待插入的顺序表,pos表示插入的位置(最小为1),value为待插入的数据
*/
static int sqlist_insert(sqlist_t* sq, int pos, int value)
{
if (sq->len > MAX_LEN || pos<1 || pos > sq->len+1)//错误处理
{
return -1;
}
for (int i = sq->len - 1;i >= pos-1;i--)
{
sq->data[i + 1] = sq->data[i];//依次往后移动
}
sq->data[pos - 1] = value;// 对插入位置赋值
sq->len++;//长度记得+1
return 0;
}
static void sqlist_show(sqlist_t* sq) //打印函数
{
for (int i = 0;i < sq->len;i++)
{
printf("%d ",sq->data[i]);
}
printf("\n");
}
int main()
{
sqlist_t* s = sqlist_init();
for (int i = 0;i < 4;i++)
{
sqlist_insert(s,i+1,i+1);//利用循环插入 1 2 3 4
}
sqlist_show(s);
sqlist_insert(s, 3, 5);//在第三个位置,即2和3之间插入5
sqlist_show(s);
return 0;
}
输出结果:
删除元素
用一个指针p将要删除位置的元素读走后,其余元素依次移动一位,最后更新顺序表的长度(减一)。
static int sqlist_delete(sqlist_t* sq, int pos,int* p)
{
if (pos<1 || pos>sq->len || sq->len > MAX_LEN)
{
return -1;
}
*p = sq->data[pos - 1];
for(int i=pos;i<sq->len;i++)
{
sq->data[i - 1] = sq->data[i];
}
sq->len--;
return 0;
}
int main()
{
int p;
sqlist_t* s = sqlist_init();
for (int i = 0;i < 4;i++)
{
sqlist_insert(s,i+1,i+1);
}
sqlist_show(s);
sqlist_insert(s, 3, 5);
sqlist_show(s);
sqlist_insert(s, 4, 3);
sqlist_show(s);
sqlist_insert(s, 5, 7);
sqlist_show(s);
sqlist_delete(s, 6,&p);
sqlist_show(s);
return 0;
}
输出结果:
查找元素
对数组的查找操作可以有很多种优化方法,本文暂时只介绍最基本的。
static int sqlist_search(sqlist_t* sq,int value)
{
for (int i = 0;i < sq->len;i++)
{
if (sq->data[i] == value)
{
return i + 1;//对数组进行暴力搜索,找到目标值就返回其位置,否则返回-1
}
}
return -1;
}
int main()
{
int p;
sqlist_t* s = sqlist_init();
for (int i = 0;i < 4;i++)
{
sqlist_insert(s,i+1,i+1);
}
sqlist_show(s);
sqlist_insert(s, 3, 5);
sqlist_show(s);
sqlist_insert(s, 4, 3);
sqlist_show(s);
sqlist_insert(s, 5, 7);
sqlist_show(s);
sqlist_delete(s, 6,&p);
sqlist_show(s);
int res = sqlist_search(s, 7);
if (res > 0)
{
printf("找到了7,位置为:%d\n", res);
}
else
printf("没找到7\n");
int res2 = sqlist_search(s, 9);
if (res2 > 0)
{
printf("找到了9,位置为:%d\n", res2);
}
else
printf("没找到9\n");
return 0;
}
输出结果:
修改元素
这里的逻辑就是直接对要修改的位置重新赋值。
static int sqlist_alter(sqlist_t* sq, int pos, int new)
{
if (pos > sq->len || sq->len > MAX_LEN)
{
return -1;//错误处理
}
sq->data[pos - 1] = new;//直接对要修改的位置重新赋值
return 0;
}
int main()
{
int p;
sqlist_t* s = sqlist_init();
for (int i = 0;i < 4;i++)
{
sqlist_insert(s,i+1,i+1);
}
sqlist_show(s);
sqlist_insert(s, 3, 5);
sqlist_show(s);
sqlist_insert(s, 4, 3);
sqlist_show(s);
sqlist_insert(s, 5, 7);
sqlist_show(s);
sqlist_delete(s, 6,&p);
sqlist_show(s);
int res = sqlist_search(s, 7);
if (res > 0)
{
printf("找到了7,位置为:%d\n", res);
}
else
printf("没找到7\n");
sqlist_alter(s, res, 9);
sqlist_show(s);
int res1 = sqlist_search(s, 7);
if (res1 > 0)
{
printf("找到了7,位置为:%d\n", res1);
}
else
printf("没找到7\n");
int res2 = sqlist_search(s, 9);
if (res2 > 0)
{
printf("找到了9,位置为:%d\n", res2);
}
else
printf("没找到9\n");
return 0;
}
输出结果: