数据结构与算法学习笔记一---线性表的实现(C语言)

目录

2.线性表的实现

1.线性表的顺序存储表示

1.定义

2.初始化

3.判断是否为空表

4.求表长

5.查找

6.查询直接前驱节点

7.查询直接后继节点

8. 插入顺序表插入

9.删除节点

10.遍历顺序表

11.完整代码

2.线性表的链式存储表示

1.定义

2.初始化

3.判断是否为空表

4.求表长

5.查找

6.查询直接前驱节点

7.查询直接后继节点

8. 插入

9.删除节点

10.遍历顺序表

11.完整代码


    由n(n≥0)个数据特性相同的元素构成的有限序列称为线性表。线性表中元素的个数n(n≥0)定义为线性表的长度,n=0时称为空表。对于非空的线性表或线性结构,其特点是:
(1)存在唯一的一个被称作“第一个”的数据元素;
(2)存在唯一的一个被称作“最后一个”的数据元素;
(3)除第一个之外,结构中的每个数据元素均只有一个前驱;
(4)除最后一个之外,结构中的每个数据元素均只有一个后继

2.线性表的实现

        线性表有顺序存储和链式存储两种表示方法。

1.线性表的顺序存储表示

        顺序表是一种线性表的存储结构,它用一组地址连续的存储单元依次存储线性表的数据元素。顺序表中的元素在物理位置上是连续存储的,这使得顺序表在存取元素时具有良好的随机访问性能。

        在 C 语言中,顺序表通常通过数组来实现。每个元素在数组中的下标可以作为该元素在顺序表中的位置,因此可以直接通过下标访问或修改元素,具有较高的访问效率。

1.定义

#define MAXSIZE 100 //顺序表的最大长度
#define ElementType inttypedef struct {ElementType *element; // 存储空间基地址int length;           // 当前长度
} SeqList;

2.初始化

        初始化线性表的时候,我们需要先给线性表分配存储空间,然后把线性表的表长置空。

// 初始化
int initSeqList(SeqList *seqList) {seqList->element = (ElementType *)malloc(sizeof(ElementType) * MAXSIZE);if (seqList->element == NULL) { // 初始化失败printf("初始化分配空间失败!\n");return 0;}seqList->length = 0;return 1;
}

3.判断是否为空表

int seqListIsEmpty(SeqList *seqList){return seqList->length == 0;
}

4.求表长

int seqListLength(SeqList *seqList){int length = seqList->length;return length;
}

5.查找

        一个是根据下标查找,这种查找结构是唯一的。还有就是根据元素查找,这里返回的是第一个和要查找的元素相同的元素下标。

int getElement(SeqList *seqList,int location,int * element){if (location < 1 || location > seqList->length) {printf("非法位置\n");return 0;}if (seqList->length < 1) {printf("非法顺序表");return 0;}* element = seqList->element[location-1];return 1;
}
int getLocate(SeqList *seqList,ElementType element){for (int i = 0; i<seqList->length; i++) {if (seqList->element[i] == element) {return i;}}return -1;
}

6.查询直接前驱节点

        遍历顺序表,先查看节点是否存在,在查看前驱节点。

// 查询直接前驱节点
int priorElement(SeqList *seqList,ElementType element, ElementType * previousLlement){int hasExistElement = 0;int index = -1;for (int i = 0; i < seqList->length ; i++) {if (seqList->element[i] == element) {index = i;hasExistElement = 1;}}if (hasExistElement) {if (index <= 0) {//第1个元素没有前驱节点return 0;} else {* previousLlement = seqList->element[index - 1];return 1;}} else {return 0;}
}

7.查询直接后继节点

        遍历顺序表,先查看节点是否存在,在判断是否有后继节点。

// 查询直接后继节点
int nextElement(SeqList *seqList,ElementType element, ElementType * nextElement){int hasExistElement = 0;int index = -1;for (int i = 0; i < seqList->length ; i++) {//判断后继节点是否存在if (seqList->element[i] == element) {index = i;hasExistElement = 1;}}if (hasExistElement) {if (index >= seqList->length-1) {//最后一个节点没有后继节点return 0;} else {* nextElement = seqList->element[index + 1];return 1;}} else {return 0;}
}

8. 插入顺序表插入

        判断下要插入的位置是否合法以及存储空间是否已经满了。

// 插入顺序表插入
void insertSeqList(SeqList *seqList, int location, ElementType  element) {if (location < 1 || location > seqList->length + 1) {printf("插入位置非法,insertSeqList方法插入❎\n");return;}if (seqList->length == MAXSIZE) {//存储空间已满printf("数组存储已满");return ;}for (int j = seqList->length; j >= location; j--) {seqList->element[j] = seqList->element[j - 1];}seqList->element[location - 1] = element;seqList->length++;printf("insertSeqList方法插入✅\n");
}

9.删除节点

        遍历顺序表,根据下标找到要删除掉元素,表长减一。

// 删除节点
int deleteElement(SeqList *seqList,int position){if (position < 1 || position > seqList->length) {//非法位置return 0;}for (int i = position - 1; i<seqList->length -1; i++) {seqList->element[i] = seqList->element[i+1];}seqList->length--;return 1;
}

10.遍历顺序表

        我们使用for循环遍历顺序表。

// 遍历顺序表
void traverseList(SeqList *seqList){for (int i = 0; i < seqList->length; i++) {printf("%d\t", seqList->element[i]);}printf("\n");
}

11.完整代码

        在这里。

2.线性表的链式存储表示

        线性表的链式存储表示使用链表来实现。链表是一种数据结构,由一系列节点组成,每个节点包含数据元素和指向下一个节点的指针(或链接)。在链表中,每个节点的地址不一定是连续的,而是通过指针相互链接起来。

        线性表的链式存储表示具有动态的内存分配特性,可以根据需要动态地分配和释放内存,因此可以有效地利用内存空间,并且不受固定大小的限制。此外,链式存储结构支持高效的插入和删除操作,但访问元素时需要遍历链表,效率较低。

1.定义

#define ElementType inttypedef struct LNode{ElementType data;//数据域struct LNode * next; //指针域
}LNode,*LinkList; //LinkList为指向结构体LNode的指针

2.初始化

        初始化线性表的时候,我们需要先给线性表分配存储空间,然后把线性表的表长置空。

// 初始化
int initSeqList(SeqList *seqList) {seqList->element = (ElementType *)malloc(sizeof(ElementType) * MAXSIZE);if (seqList->element == NULL) { // 初始化失败printf("初始化分配空间失败!\n");return 0;}seqList->length = 0;return 1;
}

3.判断是否为空表

int LinkListEmpty(LinkList linkList){if (linkList->next == NULL) {return 1;}return 0;
}

4.求表长

int linkListLength(LinkList list){LNode * head = list;//头结点int length = 0;while (head->next != NULL) {head = head->next;length++;}return length;
}

5.查找

        一个是根据下标查找,这种查找结构是唯一的。还有就是根据元素查找,这里返回的是第一个和要查找的元素相同的元素下标。

//
int getElement(LinkList linkList,int i,int * element){LNode *current = linkList->next; // 从头结点的下一个节点开始遍历int j = 1;while (current != NULL && j< i) {printf("第%d个元素的值为:%d \n",j, current->data);current = current->next;j++;}if (!current || j > i) {//第i个元素不存在return 0;}* element = current->data;return 1;
}

6.查询直接前驱节点

        遍历单链表,先查看节点是否存在,在查看前驱节点。

// 查找单链表中的元素的前驱节点
int getPriorElement(LinkList linkList,int element,int * previousElement){LNode * previous = linkList;      // 头结点LNode * current = linkList->next; // 头结点的下一个节点while (current != NULL &&current->data != element) {previous  = current;current = current-> next;}if (previous->next == NULL) {return 0;}else{* previousElement = previous->data;return 1;}
}

7.查询直接后继节点

        遍历单链表,先查看节点是否存在,在判断是否有后继节点。

// 查找单链表中的元素的后继节点
int getNextElement(LinkList linkList,int element,int * nextElement){LNode * current = linkList->next; // 头结点的下一个节点while (current != NULL &&current->data != element) {current = current-> next;}if (current->next == NULL) {return 0;}else{* nextElement = current->next->data;return 1;}
}

8. 插入

        申请一个新的节点,修改要插入的节点的位置的指针域。

// 向链表中插入一个新的节点(在链表头部插入)
void insertLinkList(LinkList L, int value) {LNode *newNode = (LNode *)malloc(sizeof(LNode));if (!newNode) {exit(1); // 分配内存失败则退出}newNode->data = value;newNode->next = L->next; // 新节点的next指向原头结点后面的节点L->next = newNode; // 头结点的next指向新节点
}

9.删除节点

        我们需要找到要删除的节点的前驱节点,然后修改前驱节点的指针域。

// 删除单链表
void deleteLinkList(LinkList linkList, int value) {LNode * current = linkList; // 头结点的下一个节点int j = 0;while (current != NULL && j < value -1) {//找到要删除节点的前驱节点current = current-> next;++j;}//生成一个新节点LNode *newNode = (LNode *)malloc(sizeof(LNode));if (newNode == NULL) {//内存分配失败return;}if (!(current->next)|| j > value-1) {return ;}newNode = current->next;//指向要删除的节点current->next = newNode->next;free(newNode);
}

10.遍历顺序表

        我们使用for循环遍历顺序表。

// 打印链表中的所有元素
void printLinkList(LinkList L) {LNode *current = L->next; // 从头结点的下一个节点开始遍历while (current != NULL) {printf("%d ", current->data);current = current->next;}printf("\n");
}

11.完整代码

#include <stdio.h>
#include <stdlib.h>// 定义链表节点的结构体
typedef struct LNode {int data;                // 数据域struct LNode *next;     // 指针域,指向下一个节点
} LNode, *LinkList;// 初始化链表,创建一个空链表
void inintLinkList(LinkList * linkList) {* linkList = (LinkList)malloc(sizeof(LNode));if (!*linkList) {exit(1); // 分配内存失败则退出}(*linkList)->next = NULL; // 初始化头结点的指针域为空
}
int LinkListEmpty(LinkList linkList){if (linkList->next == NULL) {return 1;}return 0;
}
int linkListLength(LinkList list){LNode * head = list;//头结点int length = 0;while (head->next != NULL) {head = head->next;length++;}return length;
}
// 查找单链表中的元素
int getElement(LinkList linkList,int i,int * element){LNode *current = linkList->next; // 从头结点的下一个节点开始遍历int j = 1;while (current != NULL && j< i) {printf("第%d个元素的值为:%d \n",j, current->data);current = current->next;j++;}if (!current || j > i) {//第i个元素不存在return 0;}* element = current->data;return 1;
}
// 查找单链表中的元素的前驱节点
int getPriorElement(LinkList linkList,int element,int * previousElement){LNode * previous = linkList;      // 头结点LNode * current = linkList->next; // 头结点的下一个节点while (current != NULL &&current->data != element) {previous  = current;current = current-> next;}if (previous->next == NULL) {return 0;}else{* previousElement = previous->data;return 1;}
}// 查找单链表中的元素的后继节点
int getNextElement(LinkList linkList,int element,int * nextElement){LNode * current = linkList->next; // 头结点的下一个节点while (current != NULL &&current->data != element) {current = current-> next;}if (current->next == NULL) {return 0;}else{* nextElement = current->next->data;return 1;}
}// 向链表中插入一个新的节点(在链表头部插入)
void insertLinkList(LinkList L, int value) {LNode *newNode = (LNode *)malloc(sizeof(LNode));if (!newNode) {exit(1); // 分配内存失败则退出}newNode->data = value;newNode->next = L->next; // 新节点的next指向原头结点后面的节点L->next = newNode; // 头结点的next指向新节点
}
// 删除单链表
void deleteLinkList(LinkList linkList, int value) {LNode * current = linkList; // 头结点的下一个节点int j = 0;while (current != NULL && j < value -1) {//找到要删除节点的前驱节点current = current-> next;++j;}//生成一个新节点LNode *newNode = (LNode *)malloc(sizeof(LNode));if (newNode == NULL) {//内存分配失败return;}if (!(current->next)|| j > value-1) {return ;}newNode = current->next;//指向要删除的节点current->next = newNode->next;free(newNode);
}// 打印链表中的所有元素
void printLinkList(LinkList L) {LNode *current = L->next; // 从头结点的下一个节点开始遍历while (current != NULL) {printf("%d ", current->data);current = current->next;}printf("\n");
}// 释放链表占用的内存
void FreeList(LinkList L) {LNode *current = L, *temp;while (current != NULL) {temp = current;current = current->next;free(temp);}
}void printDebugInformation(char * string){printf("\n********** %s **********\n",string);}
int main(int argc, const char *argv[]) {LinkList linkList;inintLinkList(&linkList); // 初始化链表//测试链表是否为空if (LinkListEmpty(linkList)) {printf("链表为空!\n");}else{printf("链表不为空!\n");}// 插入一些节点到链表中insertLinkList(linkList, 1);insertLinkList(linkList, 2);insertLinkList(linkList, 3);insertLinkList(linkList, 4);insertLinkList(linkList, 5);if (LinkListEmpty(linkList)) {printf("链表为空!\n");}else{printf("链表不为空!\n");int length = linkListLength(linkList);printf("链表长度:%d\n",length);}// 打印链表printLinkList(linkList);//测试查找方法int element;if (getElement(linkList, 1, &element)) {printf("链表第%d个元素为:%d\n",1,element);}else{printf("链表元素查找失败\n");}//测试前驱节点查找方法printDebugInformation("测试前驱节点");if (getPriorElement(linkList, 1, &element)) {//头结点printf("链表中1的前驱节点为:%d\n",element);}else{printf("没有前驱节点\n");}if (getPriorElement(linkList, 3, &element)) {//头结点printf("链表中3的前驱节点为:%d\n",element);}else{printf("没有前驱节点\n");}//测试后继节点printDebugInformation("测试后继节点");if (getNextElement(linkList, 5, &element)) {//头结点printf("链表中5的后继节点为:%d\n",element);}else{printf("5没有后继节点\n");}if (getNextElement(linkList, 4, &element)) {//头结点printf("链表中4的后继节点为:%d\n",element);}else{printf("4没有后继节点\n");}if (getNextElement(linkList, 3, &element)) {//头结点printf("链表中3的后继节点为:%d\n",element);}else{printf("没有后继节点\n");}if (getNextElement(linkList, 2, &element)) {//头结点printf("链表中2的前驱节点为:%d\n",element);}else{printf("2没有后继节点\n");}if (getNextElement(linkList, 1, &element)) {//头结点printf("链表中1的前驱节点为:%d\n",element);}else{printf("1没有后继节点\n");}printDebugInformation("测试删除节点");printf("删除之前的单链表:\n");printLinkList(linkList);deleteLinkList(linkList, 3);printf("删除之后的单链表:\n");printLinkList(linkList);//    // 释放链表内存FreeList(linkList);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/828484.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用Redis实现获取验证码,外加安全策略

安全策略 一小时内只能获取三次&#xff0c;一天内只能获取五次 Redis存储结构 代码展示 import cn.hutool.core.util.RandomUtil; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.Test; import org.spri…

学习笔记:Vue3(图片明天处理)

文章目录 1.概述1.1定义1.2特性1.3组合式API 2.基本用例-项目搭建3.项目目录介绍3.1概述3.2查看文件 4.组合式API4.1概述4.2新的API风格4.2.1概述4.2.2写法4.2.3基本用例-Setup选项使用4.2.4基本用例-语法糖写法&#xff08;重点&#xff09;4.2.5执行时机4.2.6代码特点 4.3响应…

我的读书摘记《点燃孩子的学习动力:关于儿童学习兴趣的真相》

德韦克认为乔丹的经历揭示了那些最卓越的学习者身上的一个秘密&#xff1a;人的天赋&#xff0c;是可以不断发展的&#xff01;不管早期的天赋如何&#xff0c;人终将不断超越自己&#xff0c;发展自己的天赋。 思维方式决定了学习的成功与否&#xff01;这也意味着&#xff0…

【数据结构】三、栈和队列:5.顺序队列(循环队列)(初始化,判空判满,入队,出队,实例)

文章目录 队列Queue逻辑结构物理&#xff08;存储&#xff09;结构基本操作1.顺序队列&#xff08;循环队列&#xff09;1.1初始化1.2判空&判满1.2.1判空1.2.2判满方案一方案二方案三 1.3入队循环队列 1.4出队1.5获取队头元素1.6获取队列元素个数❗1.7循环队列c实例 队列Qu…

安卓Activity的setContentView()流程分析

目录 前言一、Activity的视图加载过程1.1 视图结构1.2 流程分析1.2.1 Activity.java -->setContentView()1.2.2 Activity.java -->getWindow()1.2.3 PhoneWindow.java -->setContentView()1.2.4 PhoneWindow.java --->installDecor()1.2.4.1 PhoneWindow.java ---&…

SD-WAN怎样保障网络稳定

随着企业网络的日益复杂&#xff0c;如何确保线路的稳定性和高效性成为了网络管理的一大挑战。尤其是在线路出现故障、质量下降或拥塞时&#xff0c;如何快速响应并切换到最佳线路&#xff0c;就显得尤为重要。SD-WAN&#xff0c;作为一种新型的网络架构&#xff0c;为用户提供…

周报不止是汇报进度,如何用周报轻松提升团队协作效率?

周报是工作中常见的沟通工具&#xff0c;对于项目经理来说尤其重要。写周报不仅仅是为了完成一项任务&#xff0c;它更是项目管理中不可或缺的环节&#xff0c;它不仅有助于项目经理跟踪项目进度&#xff0c;还加强了团队成员间的沟通与协作。以下是几个关键的原因&#xff1a;…

北京车展打响新汽车“第一枪”,长安造车40年,开启“汽车机器人”时代

4月25日&#xff0c;睽违四年的2024(第十八届)北京国际汽车展览会正式启幕&#xff0c;此次车展以“新时代 新汽车”为主题&#xff0c;吸引全球1500余家主流车企及零部件制造商同台“打擂”。其中&#xff0c;长安汽车以“数智启源随你而变”为主题&#xff0c;携各子品牌及合…

掌握未来通信技术:5G核心网基础入门

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;5GC笔记仓 朋友们大家好&#xff0c;本篇文章是我们新内容的开始&#xff0c;我们本篇进入5GC的学习&#xff0c;希望大家多多支持&#xff01; 目录 一.核心网的演进2G核心网2.5G核心网3G核心网4G…

六个月滴滴实习:轻松、舒心又高薪!

不久前&#xff0c;一位在滴滴后端研发部门实习了六个月的小伙伴在牛客网上分享了他的实习体验&#xff0c; 作者详细描述了他在滴滴的实习生活。 从他的叙述中&#xff0c;我们可以感受到与其他互联网公司相比&#xff0c;滴滴的工作环境显得相对轻松和舒适。 他提到&#x…

ROS摄像机标定

文章目录 一、环境准备二、摄像头标定2.1 为什么要标定2.2 标定前准备2.2.1 标定板2.2.2 摄像头调焦 2.3 开始标定2.4 测试标定结果 总结参考资料 一、环境准备 安装usb_cam相机驱动 sudo apt-get install ros-noetic-usb-cam 安装标定功能包 sudo apt-get install ros-noet…

深度学习——常用激活函数解析与对比

1、 简介 在神经网络中&#xff0c;激活函数扮演着至关重要的角色。它们的主要目的是引入非线性因素&#xff0c;使得网络能够学习和表示更加复杂的函数映射。以下是激活函数应具备的特点&#xff0c;以及这些特点为何重要的详细解释&#xff1a; 引入非线性有助于优化网络&am…

【Ant-Desgin-React 步骤条】步骤条配合组件使用

步骤条配合组件使用 基础使用多分组进度 基础使用 /* eslint-disable no-unused-vars */ import React, { useState } from react import { Button, message, Steps, theme } from antd import After from ./components/after import Now from ./components/now const steps …

Docker 安装 Mongo

创建宿主机目录 在你的宿主机上创建必要的目录来存储 MongoDB 的数据和配置文件。这样做可以保证即使容器被删除&#xff0c;数据也能得到保留。 mkdir -p /develop/mongo/data mkdir -p /develop/mongo/config创建 MongoDB 配置文件 创建一个名为 mongod.conf 的 MongoDB 配…

RestfulApi RestTemplate代码规范介绍

1.介绍 1.1 RestfulApi Restful API 是一种设计风格&#xff0c;代表了使用 HTTP 协议构建 web 服务的一种架构原则。REST&#xff08;Representational State Transfer&#xff09;的核心思想是&#xff0c;通过 URL 定位资源&#xff0c;使用 HTTP 方法&#xff08;GET, POS…

MySQL多版本并发控制mvcc原理浅析

文章目录 1.mvcc简介1.1mvcc定义1.2mvcc解决的问题1.3当前读与快照读 2.mvcc原理2.1隐藏字段2.2版本链2.3ReadView2.4读视图生成原则 3.rc和rr隔离级别下mvcc的不同 1.mvcc简介 1.1mvcc定义 mvcc(Multi Version Concurrency Control)&#xff0c;多版本并发控制&#xff0c;是…

golang学习笔记(defer基础知识)

什么是defer defer语句用于golang程序中延迟函数的调用&#xff0c; 每次defer都会把一个函数压入栈中&#xff0c; 函数返回前再把延迟的函数取出并执行。 为了方便描述&#xff0c; 我们把创建defer的函数称为主函数&#xff0c; defer语句后面的函数称为延迟函数。延迟函数…

npm常用的命令大全(2024-04-21)

nodejs中npm常见的命令 npm主要是node包管理和发布的工具。 npm官网网址&#xff1a;npm | Homehttps://www.npmjs.com/官网英文文档&#xff1a; npm DocsDocumentation for the npm registry, website, and command-line interfacehttps://docs.npmjs.com/about-npm官网中文文…

同城便民信息小程序源码系统:相亲交友+拼车顺风车功能 带完整的安装代码包以及搭建教程

在信息化、数字化的时代&#xff0c;人们的生活越来越离不开各种智能应用。其中&#xff0c;小程序作为一种轻量级、便捷的应用形式&#xff0c;正逐渐渗透到我们日常生活的方方面面。今天&#xff0c;我们要介绍的这款“智慧同城便民信息小程序源码系统”&#xff0c;不仅集成…

每日一题:跳跃游戏II

给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - 1] 的最…