02_线性表的顺序表示和实现
版权声明:本文为博主原创文章,未经博主允许不得转载
是时候重新系统的学习/复习一遍《数据结构》了!教材用的是清华出版社严蔚敏的《数据结构》,但众所周知,这本教材中给出的都是伪C代码,没法直接在PC上编译、运行。为了自己复习以及给那些刚开始学习数据结构的小白们一些参考,我花了点时间把书中的一些代码改为C语言程序,大神请绕过!!!当然我早就了解到了,很久之前已经有人做过该事情了,不过也许自己做一遍会更有意思。
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。
存储结构定义
// -----线性表的动态分配顺序存储结构-----
#define LIST_INT_SIZE 100 // 线性表存储空间的初始分配量
#define LISTINCREMENT 10 // 线性表存储空间的分配增量
typedef int ElemType; // ElemType类型根据实际情况而定,这里假设为int型
typedef int Status;
typedef struct {
ElemType *elem; // 存储空间基址
int length; // 当前长度
int listSize; // 当前分配的存储容量(以sizeof(ElemType)为单位)
} SqList;
线性表的初始化
线性表的初始化主要是为了分配存储空间
// -----------线性表初始化-----------
Status InitList_Sq(SqList *L) {
// 构造一个空的线性表L
L->elem = (ElemType *)malloc(LIST_INT_SIZE * sizeof(ElemType));
if (!L->elem) return ERROR; // 存储分配失败
L->length = 0;
L->listSize = LIST_INT_SIZE; // 初始存储容量
return OK;
}
线性表的插入操作
线性表的插入操作是指在线性表的第i-1个数据元素和第i个数据元素之间插入一个新的数据元素,使新插入的这个数据元素成为新的第i个数据元素。
注意:一般情况下,在第i(1≤i≤n)个元素之前插入一个元素时,需将第n至第i(共n-i+1)个元素向后移动一个位置。如果插入的数据元素元素位于表尾,不需要这种移动操作!!!教材中给出的算法存在该问题,这里我已经改正了这个bug。
// ----------线性表的插入------------
Status ListInsert_Sq(SqList *L, int i, ElemType e) {
// 在线性表L中第i个位置之前插入新的元素e
// i的合法值为1≤i≤ListLength_Sq(L)+1
ElemType *p, *q;
if (i < 1 || i > L->length + 1) return ERROR; // i值不合法
if (L->length >= L->listSize) { // 当前存储空间已满,增加分配
ElemType *newbase = (ElemType *)realloc(L->elem, (L->listSize + LISTINCREMENT) * sizeof(ElemType));
if (!newbase) return ERROR; // 存储分配失败
L->elem = newbase; // 新基址
L->listSize += LISTINCREMENT; // 增加存储容量
}
q = L->elem + (i - 1); // q为插入的位置
if (i <= L->length) { // 若插入数据位置不在表尾
// 插入位置及之后的元素右移
for (p = L->elem + L->length - 1; p >= q; --p)
*(p + 1) = *p;
}
*q = e; // 插入e
++L->length; // 表长增1
return OK;
}
线性表的删除操作
线性表的删除操作是使长度为n的线性表变为长度为n-1的线性表。
注意:一般情况下,删除第i(1≤i≤n)个元素时需将从第i+1至第n(共n-1)个元素依次向前移动一个位置。如果删除的数据元素位于表尾,则不需要这种移动操作!!!教材中给出的算法存在该问题,这里我已经改正了这个bug。
// ----------线性表的删除------------
Status ListDelete_Sq(SqList *L, int i, ElemType *e) {
// 在顺序线性表L中删除第i个元素,并用e返回其值
// i的合法值为1≤i≤ListLength_Sq(L)
ElemType *p, *q;
if (L->length == 0) // 线性表为空
return ERROR;
if (i < 1 || i > L->length) // i值不合法
return ERROR;
p = L->elem + (i - 1); // p为被删除元素的位置
*e = *p; // 被删除的元素值赋给e指向的内存单元
q = L->elem + (L->length - 1); // 表尾元素的位置
if (i < L->length) { // 如果删除的元素不是最后位置的元素
for (++p; p <= q; ++p) { // 被删除元素之后的元素左移
*(p - 1) = *p;
}
}
--L->length; // 表长减1
return OK;
}
源代码
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
// -----线性表的动态分配顺序存储结构-----
#define LIST_INT_SIZE 100 // 线性表存储空间的初始分配量
#define LISTINCREMENT 10 // 线性表存储空间的分配增量
typedef int ElemType; // ElemType类型根据实际情况而定,这里假设为int型
typedef int Status;
typedef struct {
ElemType *elem; // 存储空间基址
int length; // 当前长度
int listSize; // 当前分配的存储容量(以sizeof(ElemType)为单位)
} SqList;
// -----------线性表初始化-----------
Status InitList_Sq(SqList *L) {
// 构造一个空的线性表L
L->elem = (ElemType *)malloc(LIST_INT_SIZE * sizeof(ElemType));
if (!L->elem) return ERROR; // 存储你分配失败
L->length = 0;
L->listSize = LIST_INT_SIZE; // 初始存储容量
return OK;
}
// ----------线性表的插入------------
Status ListInsert_Sq(SqList *L, int i, ElemType e) {
// 在线性表L中第i个位置之前插入新的元素e
// i的合法值为1≤i≤ListLength_Sq(L)+1
ElemType *p, *q;
if (i < 1 || i > L->length + 1) return ERROR; // i值不合法
if (L->length >= L->listSize) { // 当前存储空间已满,增加分配
ElemType *newbase = (ElemType *)realloc(L->elem, (L->listSize + LISTINCREMENT) * sizeof(ElemType));
if (!newbase) return ERROR; // 存储分配失败
L->elem = newbase; // 新基址
L->listSize += LISTINCREMENT; // 增加存储容量
}
q = L->elem + (i - 1); // q为插入的位置
if (i <= L->length) { // 若插入数据位置不在表尾
// 插入位置及之后的元素右移
for (p = L->elem + L->length - 1; p >= q; --p)
*(p + 1) = *p;
}
*q = e; // 插入e
++L->length; // 表长增1
return OK;
}
// ----------线性表的删除------------
Status ListDelete_Sq(SqList *L, int i, ElemType *e) {
// 在顺序线性表L中删除第i个元素,并用e返回其值
// i的合法值为1≤i≤ListLength_Sq(L)
ElemType *p, *q;
if (L->length == 0) // 线性表为空
return ERROR;
if (i < 1 || i > L->length) // i值不合法
return ERROR;
p = L->elem + (i - 1); // p为被删除元素的位置
*e = *p; // 被删除的元素值赋给e指向的内存单元
q = L->elem + (L->length - 1); // 表尾元素的位置
if (i < L->length) { // 如果删除的元素不是最后位置的元素
for (++p; p <= q; ++p) { // 被删除元素之后的元素左移
*(p - 1) = *p;
}
}
--L->length; // 表长减1
return OK;
}
int main(int argc, const char * argv[]) {
SqList list; // 定义一个线性表list(实质上是一个结构体)
ElemType temp; //
if (InitList_Sq(&list))
printf("线性表初始化成功!\n");
else
printf("线性表初始化失败!\n");
for (int i = 1; i <= 10; i++) // 在线性表的第1个位置连续插入10个元素1~10
ListInsert_Sq(&list, 1, i);
printf("插入%d个元素后的线性表为:", list.length);
for (int i = 0; i < list.length; i++)
printf("%d ", *(list.elem + i));
printf("\n\n");
ListDelete_Sq(&list, 3, &temp); // 删除线性表中第3个位置的元素
printf("删除第3个元素“%d“后的线性表为:", temp);
for (int i = 0; i < list.length; i++)
printf("%d ", *(list.elem + i));
printf("\n\n");
return 0;
}
输出结果:
线性表初始化成功!
插入10个元素后的线性表为:10 9 8 7 6 5 4 3 2 1
删除第3个元素“8“后的线性表为:10 9 7 6 5 4 3 2 1
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
· 程序员转型AI:行业分析