线性表相关代码(顺序表+单链表)

server/2025/3/13 16:57:40/

线性表相关代码

  • 线性表相关代码(算法命题重点)

线性表相关代码(算法命题重点)

线性表作为一种基础且重要的数据结构,在算法领域中占据着关键地位,是众多复杂算法的基石。它能够有序地存储和管理数据元素,为数据的高效处理提供了有力支持。在实际应用场景中,无论是信息管理系统中的数据存储,还是算法竞赛中的数据处理,线性表都发挥着不可或缺的作用。接下来,我们将深入探讨线性表的各种基本操作以及不同存储方式的具体实现。

基本操作
线性表的基本操作涵盖了初始化、销毁、插入、删除、查找、求表长、判空和输出表等,这些操作构成了线性表功能的核心。

InitList(&L): 初始化链表, 该操作的作用是创建一个空的线性表。
DestroyList(&L): 销毁链表, 用于释放线性表所占用的内存空间,防止内存泄漏,确保系统资源的有效利用。
ListInsert(&L, i, e):插入操作, 在指定线性表 L 的第 i 个位置上插入指定元素 e,使得线性表的元素序列发生相应变化。
ListDelete(&L, i, &e): 删除操作, 从表 L 中删除第 i 个位置上的元素,并将删除的值通过 e 返回,实现对线性表元素的移除。
GetElem(L, i):按位查找元素, 获取线性表 L 中第 i 个位置的元素的值,方便根据位置快速获取特定元素。
LocateElem(L, e):按值查找操作, 在 L 中查找与 e 值相同的元素,为根据元素值定位元素提供了途径。
Length(L): 求表长, 计算线性表 L 中元素的个数,即表的长度,有助于了解线性表的规模。
Empty(L): 判空, 判断线性表 L 是否为空,这在许多操作中是一个重要的前提条件。
PrintList(L): 输出表, 将线性表 L 中的所有元素按照一定格式输出,便于直观查看线性表的内容。

顺序存储

顺序存储是线性表的一种存储方式,它利用一组连续的存储单元依次存储线性表中的数据元素。这种存储方式具有随机访问的特性,能够快速地根据位置获取元素。

#include<stdio.h>
#include<stdlib.h>// 顺序表的定义(静态分配)
#define Maxsize 50
typedef struct{int data[Maxsize];    // 顺序表的元素int length;  // 顺序表的当前长度
}SqList;// 初始化
void initList(SqList &L){L.length = 0;
}// 插入
bool ListInsert(SqList &L, int i, int e){if(i < 1 || i > L.length + 1)return false;if(L.length >= Maxsize)return false;for(int j = L.length; j >= i; j --) // 将第i个元素及之后的元素后移L.data[j] = L.data[j - 1];L.data[i - 1] = e;L.length ++;return true;
}// 删除
bool ListDelete(SqList &L, int i, int &e){if(i < 1 || i > L.length)return false;e = L.data[i];for(int j = i; j < L.length; j ++)L.data[j] = L.data[j + 1];L.length --;return true;
}// 按值查找
int LocateElem(SqList &L, int e){for(int i = 0; i < L.length; i ++)if(L.data[i] == e)return i + 1; // 返回位序return 0;
}// 按位查找
int GetElem(SqList &L, int i){return L.data[i - 1];
}// 判空
bool Empty(SqList L){return L.length == 0;
}
// 动态分配
#define InitSize 100
typedef struct{int *data;  // 指示动态分配数组的指针int MaxSize, length; // 数组的最大容量和当前长度
}SqList;// 初始化
void initList(SqList &L){L.data = (int*)malloc(sizeiof(int) * InitSize);L.length = 0;L,MaxSize = InitSize;
}

在顺序表的静态分配实现中,我们预先定义了一个固定大小的数组 data 来存储元素,通过 length 记录当前表中元素的实际个数。初始化时,将 length 设为 0。插入操作时,首先检查插入位置 i 的合法性以及表是否已满,若满足条件,则将插入位置及之后的元素依次向后移动一位,再将新元素插入指定位置。删除操作同样先检查位置合法性,然后将待删除元素的值赋给 e,并将后续元素依次向前移动一位,同时更新表长。按值查找通过遍历整个表,找到与目标值相等的元素并返回其位序,若未找到则返回 0。按位查找直接返回指定位置的元素值。判空操作只需判断 length 是否为 0。
动态分配的顺序表中,通过 malloc 函数动态分配内存来存储元素,灵活性更高。初始化时,分配一定大小的内存空间给 data 指针,并设置初始长度和最大容量。

链式存储

链式存储是线性表的另一种重要存储方式,它通过指针将各个数据元素链接起来,克服了顺序存储需要连续内存空间的局限性。下面将详细介绍链式存储的不同类型及其实现代码。

链表

链表是链式存储的基础形式,每个节点包含数据域和指针域,指针域指向下一个节点。根据是否带有头结点,又分为带头结点和不带头结点两种情况。

带头结点
// 定义单链表的结点
typedef struct LNode{int data;struct LNode *next;
}LNode, *LinkList;// 初始化
bool InitList(LinkList &L){L = (LNode*)malloc(sizeof(LNode)); // 创建头结点if(L == NULL) // 没有空间了return false; L -> next = NULL;return true;
}// 求表长(只有头结点算空表)
int Length(LinkList L){int len = 0;LNode* p = L;while(p -> next != NULL){p = p -> next;len ++;}return len;
}// 按序查找 (找到第i个结点,头结点看作第0个)
LNode* GetElem(LinkList L, int i){if(i < 0)return NULL;LNode* p = L;while(p != NULL && i --){p = p -> next;}return p;
}// 插入节点(也可以在结点之前插入一个结点,然后交换两个结点的值)
bool ListInsert(LinkList &L, int i, int e){LNode* p = L; // 表示要插入点之前的一个结点int j = 0;while(p != NULL && j < i){ // 循环找到第 i - 1 个结点p = p -> next;j ++;}if(p == NULL) // i 不合法return false;LNode* s = (LNode*)malloc(sizeof(LNode)); // 创建一个新结点if(s == NULL) return false; // 没有足够的空间了s -> data = e;s -> next = p -> next;p -> next = s;return true;
}// 删除结点操作(同样也可以把第i- 1个结点删除,而后使用值覆盖)
bool ListDelete(LinkList &L, int i, int &e){LNode* p = L; // 表示要删除结点的前一个结点int j = 0;while(p != NULL && j < i - 1){p = p -> next;j ++;}if(p -> next == NULL || j > i - 1) // i 值不合法return false;LNode* tmp = p -> next;e = tmp -> data;p -> next = tmp -> next;free(tmp);return true;
}// 使用头插法来建立链表
LinkList List_HeadInsert(LinkList &L){ // 逆向建立单链表LNode *s;int x;InitList(L); // 初始化链表scanf("%d", &x);while(x != 9999){ // 输入9999代表结束s = (LNode*)malloc(sizeof(LNode));if(s == NULL) return false; // 没有足够的空间了s -> data = x;s -> next = L -> next;L -> next = s;scanf("%d", &x);}return L;
}// 使用尾插法
LinkList List_TailInsert(LinkList &L){int x;InitList(L); // 初始化链表LNode *s, *r = L; // r 表示表尾指针scanf("%d", &x);while(x != 9999){s = (LNode*)malloc(sizeof(LNode));if(s == NULL) return false; // 没有足够的空间了s -> data = x;r -> next = s;r = s;scanf("%d", &x);}r -> next = NULL;return L;
}
不带头结点
// 定义单链表的结点
typedef struct LNode{int data;struct LNode *next;
}LNode, *LinkList;// 初始化
bool InitList(LinkList &L){L = NULL; // 创建空表,无任何结点return true;
}// 求表长
int Length(LinkList L){int len = 0;LNode* p = L;while(p != NULL){len ++;p = p -> next;}return len;
}// 按序查找
LNode* GetElem(LinkList L, int i){if(i <= 0)return NULL;LNode *p = L;while(p != NULL && --i){p = p -> next;}return p;
}// 插入结点
bool ListInsert(LinkList &L, int i, int e){if(i == 1) {// 如果要在第一个位置插入元素LNode* p = (LNode*)malloc(sizeof(LNode));if(p == NULL) return false; // 没有足够的空间了p -> data = e;p -> next = L;L = p;return true;}LNode* p = L;int j = 0;while(p != NULL && j < i - 1){p = p -> next;j ++;}if(p == NULL)return false;LNode* s = (LNode*)malloc(sizeof(LNode));if(s == NULL) return false; // 没有足够的空间了s -> data = e;s -> next = p -> next;p -> next = s;return true;
}// 删除结点
bool ListDelete(LinkList &L, int i, int &e){if(i == 1){ // 删除第一个结点LNode* p = L;e = p -> data;L = p -> next;free(p);return true;}LNode*p = L;int j = 0;while(p -> next != NULL && j < i - 1){p = p -> next;j ++;}if(p -> next == NULL)return false;LNode* tmp = p -> next;e = tmp -> data;p -> next = tmp -> next;free(tmp);return true;
}// 使用头插法建立链表
LinkList List_HeadInsert(LinkList &L){LNode *s;int x;InitList(L); // 初始化链表scanf("%d", &x);while(x != 9999){s = (LNode*)malloc(sizeof(LNode));if(s == NULL) return false; // 没有足够的空间了s -> data = x;s -> next = L; // s是第一个结点scanf("%d", &x);}return L;
}// 使用尾插法建立链表
LinkList List_TailInsert(LinkList &L){int x;InitList(L); // 初始化LNode *s, *r = L; scanf("%d", &x);while(x != 9999){s = (LNode*)malloc(sizeof(LNode));if(s == NULL) return false; // 没有足够的空间了s -> data = x;r -> next = s;r = s;scanf("%d", &x);}r -> next = NULL;return L;
}

剩下的会在下一篇博客中呈现,敬请期待!

链表

循环链表

静态链表


http://www.ppmy.cn/server/174673.html

相关文章

go sync.Once 源码分析

sync.Once 是 Go 语言标准库中的一个同步原语&#xff0c;用于确保某个操作或函数在并发环境下只执行一次。它通常用于以下场景&#xff1a; 单例模式&#xff1a;确保全局只有一个实例对象&#xff0c;避免重复创建资源延迟初始化&#xff1a;在程序运行过程中&#xff0c;当…

无需 Docker 也能下载镜像!轻松获取 Docker 镜像文件!

背景问题 在日常开发或运维工作中&#xff0c;我们经常需要下载 Docker 镜像&#xff0c;但可能会遇到以下问题&#xff1a; &#x1f539; 服务器无法访问 Docker Hub&#xff0c;导致 docker pull 失败。 &#x1f539; Windows 端没有安装 Docker&#xff0c;但仍然需要获…

Pygame实现射击鸭子游戏3-1

基于pygame的打鸭子游戏如图1所示。 图1 打鸭子游戏 从图1中可以看出&#xff0c;玩家通过鼠标控制瞄准镜的移动&#xff0c;点击鼠标左键射击鸭子。而鸭子则从屏幕左边向右边游动&#xff0c;当游到屏幕右侧边界后&#xff0c;重新回到屏幕左侧继续游动。 游戏需要创建两个类…

STM32外部中断

GPIO->AFIO->EXTI->NVIC 进入NVIC是中断 不进入NVIC是事件 AFIO复用重映射 IP[59]~IP[0]分别对应中断 59~0。而每个可屏蔽中断占用的 8bit 并没有 全部使用&#xff0c;而是只用了高 4 位。这 4 位&#xff0c;又分为抢占优先级和子优先级。抢占优先级在前&#xf…

【C++】滑动窗口算法

繁花落尽&#xff0c;我心中仍有花落的声音。一朵&#xff0c;一朵&#xff0c;在无人的山间轻轻飘落。 前言 这是我自己学习蓝桥杯算法的第二篇博客总结。 上一期笔记是关于C的双指针算法&#xff0c;没看的同学可以过去看看&#xff1a; 【C】双指针算法-CSDN博客https://bl…

iOS侧滑返回手势冲突处理

遇到这样一个场景&#xff0c;本身页面vc.view添加了全屏侧滑返回手势&#xff0c; 但是页面中顶部有一个横向滚动的collectionView&#xff0c; 这个时候&#xff0c;我们 如果在页面总滑动横向滚动的collectionView的时候&#xff0c;就会执行横向collectionView的滚动&#…

分布式存储学习——HBase表结构设计

目录 1.4.1 模式创建 1.4.2 Rowkey设计 1.4.3 列族定义 1.4.3.1 可配置的数据块大小 1.4.3.2 数据块缓存 1.4.3.3 布隆过滤器 1.4.3.4 数据压缩 1.4.3.5 单元时间版本 1.4.3.6 生存时间 1.4.4 模式设计实例 1.4.4.1 实例1&#xff1a;动物分类 1.4.4.2 …

Python零基础学习第三天:函数与数据结构

一、函数基础 函数是什么&#xff1f; 想象你每天都要重复做同一件事&#xff0c;比如泡咖啡。函数就像你写好的泡咖啡步骤说明书&#xff0c;每次需要时直接按步骤执行&#xff0c;不用重新想流程。 # 定义泡咖啡的函数 def make_coffee(sugar1): # 默认加1勺糖 print("…