《数据结构》数据结构概念,顺序表,链表

目录

1. 为什么学习数据结构?

2. 数据结构

2.1. 数据

2.2. 逻辑结构

2.3. 存储结构

2.4. 操作

3. 算法

3.1. 算法与程序

3.2. 算法与数据结构

3.3. 算法的特性

3.4. 如何评价一个算法的好坏

4. 线性表

4.1. 顺序表

4.2. 单向链表

4.3. 单向循环链表(解决约瑟夫问题)


1. 为什么学习数据结构?

C语言:学习的时如何写代码

数据结构:教会我们高效简洁的写代码。

实现一个功能、写代码解决什么问题?

1》数据与数据之间的逻辑规律和数据在计算机中如何表示(存储)

数据结构:数据的逻辑结构存储结构及操作

数据:不只是一个单独的数值、是一个集合的概念。

2》解决问题的方法(实现代码的逻辑思想)

算法

数据结构+算法=程序

2. 数据结构

概念: 数据的逻辑结构存储结构及操作。

2.1. 数据

数据:不只是一个单独的数值,是一个集合的概念。

数据元素:数据的最小单位,由基本的数据项构成。

数据项:是数据元素的基本单位,描述数据元素拥有的信息。

节点:就是数据元素

2.2. 逻辑结构

概念:描述数据之间的逻辑规律和联系,即元素与元素之间的关系

逻辑结构的分类:

  1. 线性结构(头节点无前驱,尾节点无后缀)
    1. 线性存储
    2. 一对一的关系
    3. 顺序表、链表
  1. 层次结构(根节点无前驱,叶子节点无后继)
    1. 一对多的关系
  1. 网状结构
    1. 多对多的关系

2.3. 存储结构

概念:数据的逻辑结构在计算机中的具体实现

  1. 存储结构分类
    1. 顺序存储:内存空间开辟是连续(数组:内存空间连续开辟,数据元素类型相同)
    2. 链式存储:通过地址数据元素联系在一起
    3. 索引存储:通过索引表找到数据元素存放位置,拿到数据
    4. 散列存储结构 (哈希存储)
      1. 数据元素的存放和位置之间存在一个关系。
      2. 存在一个关键字key和一个关系函数,通过关键值key带入关系函数计算出数据存放的位置。对应位置存放、对应位置取值。

2.4. 操作

操作:增 删 改 查

3. 算法

3.1. 算法与程序

算法:解决问题的思想办法

程序:用计算机语言对算法的具体实现

3.2. 算法与数据结构

算法+数据结构=程序

算法的设计:依赖于逻辑结构

算法的实现:依赖于存储结构

3.3. 算法的特性

  1. 有穷性:算法的执行步骤是有限的
  2. 确定性:算法的每一个步骤,无二义性 ,没有歧义
  3. 可行性:算法能够在有限的时间内完成
  4. 输入和输出:一个算法可以有一个或多个输入和输出

3.4. 如何评价一个算法的好坏

  1. 正确性:保证算法能够正确的完成功能的实现
  2. 易读性:算法容易被解读
  3. 健壮性:错误处理
  4. 高效性:算法执行效率,算法执行快慢容易受到计算机性能的
  5. 低存储性:算法占用空间小,空间复杂度

4. 线性表

  • 线性表:
    • 顺序表
    • 链表(单向链表 单向循环链表 双向链表 双向循环链表)
    • 队列
  • 特点:一对一的关系,头节点没有前驱,尾节点没有后继

4.1. 顺序表

  • 特点:内存空间是连续开辟(数组)
  • 逻辑结构:线性结构
  • 存储结构:顺序存储结构
  • 定义一个结构体表示顺序表
#define  N 10
typedef  int   datatype_t;
typedef struct  list_t{datatype_t  data[N];//表int last ;			//保存最后一个有效元素的下标 (-1 表为空)}seqlist_t,*seqlist_pj;
 
  • 常见操作
#include <stdio.h>
#include <stdlib.h>#define N 10typedef int datatype_t;typedef struct list_t {datatype_t data[N]; 	// 表int last; 				// 保存最后一个有效元素的下标 (-1 表为空)
} seqlist_t, *seqlist_p;// 创建一个空的顺序表
seqlist_p createList() {seqlist_p list = (seqlist_p)malloc(sizeof(seqlist_t));list->last = -1;return list;
}// 向顺序表的指定位置插入数据
void insert(seqlist_p list, int pos, int value) {if (pos < 0 || pos > list->last + 1 || list->last == N - 1) {printf("插入位置无效或顺序表已满\n");return;}// 将插入位置之后的元素依次后移for (int i = list->last; i >= pos; i--) {list->data[i+1] = list->data[i];}// 在指定位置插入新元素list->data[pos] = value;list->last++;
}// 判断顺序表是否满
int isFull(seqlist_p list) {return list->last == N - 1;
}// 指定位置删除数据
void delete(seqlist_p list, int pos) {if (pos < 0 || pos > list->last) {printf("删除位置无效\n");return;}// 将删除位置之后的元素依次前移for (int i = pos; i < list->last; i++) {list->data[i] = list->data[i+1];}list->last--;
}// 判断顺序表是否为空
int isEmpty(seqlist_p list) {return list->last == -1;
}// 修改指定位置的数据
void modify(seqlist_p list, int pos, int value) {if (pos < 0 || pos > list->last) {printf("修改位置无效\n");return;}list->data[pos] = value;
}// 删除指定的数据
void removeData(seqlist_p list, int value) {for (int i = 0; i <= list->last; i++) {if (list->data[i] == value) {// 将删除位置之后的元素依次前移for (int j = i; j < list->last; j++) {list->data[j] = list->data[j+1];}list->last--;i--; // i减1以继续判断下一个元素是否与value相等}}
}// 清空顺序表
void clearList(seqlist_p list) {list->last = -1;
}// 删除顺序表
void deleteList(seqlist_p list) {free(list);
}// 遍历顺序表
void traverse(seqlist_p list) {if (isEmpty(list)) {printf("顺序表为空\n");return;}printf("顺序表数据:");for (int i = 0; i <= list->last; i++) {printf("%d ", list->data[i]);}printf("\n");
}int main() {seqlist_p list = createList();insert(list, 0, 1);insert(list, 1, 2);insert(list, 2, 3);traverse(list);delete(list, 1);traverse(list);modify(list, 0, 5);traverse(list);removeData(list, 5);traverse(list);clearList(list);traverse(list);deleteList(list);return 0;
}
 
  • 顺序表的特点

1.内存空间连续开辟

2.长度固定(保存的数据元素个数是固定的) #define N 10

3.插入和删除比较复杂,查询操作或修改比较简单。

4.2. 单向链表

  • 特点:内存空间开辟不是连续、通过地址将多有的内存空间练习到一起
  • 逻辑结构:线性结构
  • 存储结构:链式存储
  • 分类:
    • 有头单向链表
      • 链表中的头节点数据域无效,指针域有效
    • 无头单向链表
      • 链表中所有节点的数据域和指针域都是有效的
  • 定义链表节点结构体:
typedef  int  datatype_t;
typedef struct  node_t 		//node 节点
{datatype_t data;		//数据域struct node_t *next;	//指针域		保存下一个节点的地址
}linklist_t,*linklist_p;	//link		链
 
  • 有头单向链表
#include <stdio.h>
#include <stdlib.h>typedef int datatype_t;
typedef struct node_t
{datatype_t data;		//数据域struct node_t *next;	//节点域
}linklist_t, *linklist_p;// 创建空的有头单向链表
void createEmptyList(linklist_p *head)
{*head = (linklist_p)malloc(sizeof(linklist_t));(*head)->next = NULL;
}// 向链表的指定位置插入数据
void insertData(linklist_p head, int position, datatype_t data)
{linklist_p p = head;int count = 0;while (p && count < position){p = p->next;count++;}if (p && count == position){linklist_p newNode = (linklist_p)malloc(sizeof(linklist_t));newNode->data = data;newNode->next = p->next;p->next = newNode;}
}// 计算链表的长度
int calculateLength(linklist_p head)
{linklist_p p = head->next;int length = 0;while (p){length++;p = p->next;}return length;
}// 遍历链表
void traverseList(linklist_p head)
{linklist_p p = head->next;while (p){printf("%d ", p->data);p = p->next;}printf("\n");
}// 删除链表指定位置的节点
void deleteNode(linklist_p head, int position)
{linklist_p p = head;int count = 0;while (p && count < position){p = p->next;count++;}if (p && p->next && count == position){linklist_p temp = p->next;p->next = p->next->next;free(temp);}
}// 修改链表指定位置的数据
void modifyData(linklist_p head, int position, datatype_t data)
{linklist_p p = head->next;int count = 0;while (p && count < position){p = p->next;count++;}if (p && count == position){p->data = data;}
}// 查询指定数据的位置
int findPosition(linklist_p head, datatype_t data)
{linklist_p p = head->next;int position = 0;while (p){if (p->data == data){return position;}p = p->next;position++;}return -1;
}// 删除指定的数据
void deleteData(linklist_p head, datatype_t data)
{linklist_p p = head;while (p->next){if (p->next->data == data){linklist_p temp = p->next;p->next = p->next->next;free(temp);}else{p = p->next;}}
}// 清空链表
void clearList(linklist_p head)
{linklist_p p = head->next;while (p){linklist_p temp = p;p = p->next;free(temp);}head->next = NULL;
}// 链表的倒置
void reverseList(linklist_p *head)
{linklist_p prev = NULL;linklist_p current = *head;linklist_p next = NULL;while (current != NULL){next = current->next;current->next = prev;prev = current;current = next;}*head = prev;
}// 判断链表是否为空
int isEmpty(linklist_p head)
{return head->next == NULL;
}int main()
{linklist_p head;createEmptyList(&head);insertData(head, 0, 1);insertData(head, 1, 2);insertData(head, 2, 3);insertData(head, 3, 4);insertData(head, 4, 5);printf("List: ");traverseList(head);printf("Length: %d\n", calculateLength(head));deleteNode(head, 2);printf("After deleting node at position 2: ");traverseList(head);modifyData(head, 1, 10);printf("After modifying data at position 1: ");traverseList(head);int position = findPosition(head, 5);printf("Position of data 5: %d\n", position);deleteData(head, 1);printf("After deleting data 1: ");traverseList(head);clearList(head);printf("After clearing the list: ");traverseList(head);insertData(head, 0, 1);insertData(head, 1, 2);insertData(head, 2, 3);insertData(head, 3, 4);insertData(head, 4, 5);printf("List: ");traverseList(head);reverseList(&head);printf("After reversing the list: ");traverseList(head);printf("Is list empty? %s\n", isEmpty(head) ? "Yes" : "No");return 0;
}
 
  • 无头单向链表
#include <stdio.h>
#include <stdlib.h>// typedef定义的数据类型
typedef int datatype_t;
typedef struct node_t {datatype_t data;struct node_t* next;
} linklist_t, * linklist_p;// 创建空的有头单向链表
void createEmptyList(linklist_p* head) {*head = NULL;
}// 向链表的指定位置插入数据
int insertElement(linklist_p* head, int position, datatype_t value) {// 创建新节点linklist_p new_node = (linklist_p)malloc(sizeof(linklist_t));if (new_node == NULL) {return 0;  // 内存分配失败}new_node->data = value;new_node->next = NULL;if (position == 0) {new_node->next = *head;*head = new_node;}else {int count = 0;linklist_p current = *head;while (current != NULL && count < position - 1) {current = current->next;count++;}if (current == NULL) {return 0;  // 指定位置无效}new_node->next = current->next;current->next = new_node;}return 1;
}// 计算链表的长度
int getLength(linklist_p head) {int length = 0;linklist_p current = head;while (current != NULL) {length++;current = current->next;}return length;
}// 遍历链表
void traverse(linklist_p head) {linklist_p current = head;while (current != NULL) {printf("%d ", current->data);current = current->next;}printf("\n");
}// 删除链表指定位置的数据
int deleteElement(linklist_p* head, int position) {if (*head == NULL) {return 0;  // 链表为空}if (position == 0) {linklist_p temp = *head;*head = (*head)->next;free(temp);}else {int count = 0;linklist_p current = *head;linklist_p previous = NULL;while (current != NULL && count < position) {previous = current;current = current->next;count++;}if (current == NULL) {return 0;  // 指定位置无效}previous->next = current->next;free(current);}return 1;
}// 修改链表指定位置的数据
int modifyElement(linklist_p head, int position, datatype_t value) {int count = 0;linklist_p current = head;while (current != NULL && count < position) {current = current->next;count++;}if (current == NULL) {return 0;  // 指定位置无效}current->data = value;return 1;
}// 查询指定数据的位置
int findPosition(linklist_p head, datatype_t value) {int position = 0;linklist_p current = head;while (current != NULL) {if (current->data == value) {return position;}current = current->next;position++;}return -1;  // 没有找到指定数据
}// 删除指定的数据
int deleteValue(linklist_p* head, datatype_t value) {if (*head == NULL) {return 0;  // 链表为空}if ((*head)->data == value) {linklist_p temp = *head;*head = (*head)->next;free(temp);return 1;}linklist_p current = *head;linklist_p previous = NULL;while (current != NULL && current->data != value) {previous = current;current = current->next;}if (current == NULL) {return 0;  // 没有找到指定数据}previous->next = current->next;free(current);return 1;
}// 清空链表
void clearList(linklist_p* head) {linklist_p current = *head;while (current != NULL) {linklist_p temp = current;current = current->next;free(temp);}*head = NULL;
}// 链表的倒置
void reverseList(linklist_p* head) {linklist_p previous = NULL;linklist_p current = *head;linklist_p next = NULL;while (current != NULL) {next = current->next;current->next = previous;previous = current;current = next;}*head = previous;
}// 判断链表是否为空
int isListEmpty(linklist_p head) {return head == NULL;
}int main() {linklist_p linked_list;createEmptyList(&linked_list);insertElement(&linked_list, 0, 1);insertElement(&linked_list, 1, 2);insertElement(&linked_list, 2, 3);insertElement(&linked_list, 3, 4);traverse(linked_list);  // 输出: 1 2 3 4printf("Length: %d\n", getLength(linked_list));  // 输出: 4deleteElement(&linked_list, 2);traverse(linked_list);  // 输出: 1 2 4modifyElement(linked_list, 1, 5);traverse(linked_list);  // 输出: 1 5 4int position = findPosition(linked_list, 5);printf("Position: %d\n", position);  // 输出: 1deleteValue(&linked_list, 1);traverse(linked_list);  // 输出: 5 4clearList(&linked_list);printf("Is empty: %s\n", isListEmpty(linked_list) ? "Yes" : "No");  // 输出: YesinsertElement(&linked_list, 0, 1);insertElement(&linked_list, 1, 2);insertElement(&linked_list, 2, 3);insertElement(&linked_list, 3, 4);traverse(linked_list);  // 输出: 1 2 3 4reverseList(&linked_list);traverse(linked_list);  // 输出: 4 3 2 1return 0;
}
 
  • 链表的特点

1.内存空间不连续,通过地址将地址空间联系在一起

2.长度不固定

3.删除和插入简单,查询和修改复杂

4.3. 单向循环链表(解决约瑟夫问题)

  • 特点:无头单向链表尾节点的指针域保存头节点的地址, 就可以形成单向循环链表
  • 通过一定规律找到一个最终的值
  • 定义链表结构体
typedef struct node_t
{int data;struct node_t *next;
}link_t;
  • 单向循环链表
#include <stdio.h>
#include <stdlib.h>
#define N 10
typedef struct node_t
{int data;struct node_t *next;
} link_t;int main()
{// 1.创建一个单向无头链表link_t *tail = NULL;link_t *p = (link_t *)malloc(sizeof(link_t));if (p == NULL){puts("mallod error");return -1;}p->data = 1;p->next = NULL;tail = p; // 指针tail指向了p// 创建接下来的节点for (int i = 0; i < N; i++){tail->next = (link_t *)malloc(sizeof(link_t));if (tail->next == NULL){puts("mallod error");return -1;}tail = tail->next;tail->data = i + 1;tail->next = NULL;}tail->next = p; // 尾节点指向头节点// 解决约瑟夫问题int start_num = 3;int n = 3;link_t *pdel = NULL;// 1.将头指针移动到Kfor (int i = 0; i < start_num - 1; i++){p = p->next;}pdel = p->next;while (p != p->next){for (int i = 0; i < n - 1; i++)p = p->next;pdel = p->next;p->next = pdel->next;free(pdel);pdel = NULL;}printf("king is %d\n", p->data);return 0;
}

顺序表和单向链表比较

顺序表

链表

空间

空间连续

通过指针链接

长度

固定

不固定

特点

查找方便,但是插入和删除麻烦

插入方便,查找麻烦

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

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

相关文章

SpringBoot使用Redis作为缓存器缓存数据的操作步骤以及避坑方案

1.非注解式实现 2.1使用之前要明确使用的业务场景 例如我们在登录时&#xff0c;可以让redis缓存验证码&#xff0c;又如在分类下显示菜品数据时&#xff0c;我们可以对分类和菜品进行缓存数据等等。 2.2导入Redis相关依赖 <dependency><groupId>org.springfra…

SpringAMQP - 消息传输时,如何提高性能?解决 SQL 注入问题?

目录 一、问题背景 二、从消息转化器根源解决问题 1.引入依赖 2.在服务生产者和消费者中都重新定义一个 MessageConverter&#xff0c;注入到 Spring 容器中 一、问题背景 在SpringAMQP的发送方法中&#xff0c;接收消息的类型是Object&#xff0c;也就是说我们可以发送任意…

DB-Engines排名公布 GBASE南大通用入围国产数据库TOP 3

什么是DB-Engines排名&#xff1f; DB-Engines排名是数据库领域的流行度榜单&#xff0c;它对全球范围内的419款数据库&#xff08;截至2023年7月&#xff09;进行排名&#xff0c;每月更新一次&#xff0c;排名越靠前&#xff0c;则表示越流行。在很多技术选型的场合&#xf…

【idea】idea全局设置Maven配置

Idea版本&#xff1a;2021.1.1 1、点击File->Close project 2、点击Customize->All settings 3、设置Maven

# Linux终端控制字符详解以及简单应用实践

Linux终端控制字符详解以及简单应用实践 文章目录 Linux终端控制字符详解以及简单应用实践1 控制字符表2 控制字符 ESC &#xff08;0x1B&#xff0c;^[&#xff09;子参数表3 控制字符 ESC &#xff08;0x1B&#xff0c;^[&#xff09;子参数表 - 字符颜色参照表4 实践&#x…

Python实现HBA混合蝙蝠智能算法优化循环神经网络分类模型(LSTM分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蝙蝠算法是2010年杨教授基于群体智能提出的启发式搜索算法&#xff0c;是一种搜索全局最优解的有效方法…

2023无监督摘要顶会论文合集

2023无监督摘要顶会论文合集 写在最前面ACL-2023Aspect-aware Unsupervised Extractive Opinion Summarization 面向的无监督意见摘要&#xff08;没找到&#xff09;Unsupervised Extractive Summarization of Emotion Triggers *情绪触发(原因)的 *无监督 *抽取式 摘要&#…

DETR (DEtection TRansformer)基于自建数据集开发构建目标检测模型超详细教程

目标检测系列的算法模型可以说是五花八门&#xff0c;不同的系列有不同的理论依据&#xff0c;DETR的亮点在于它是完全端到端的第一个目标检测模型&#xff0c;DETR&#xff08;Detection Transformer&#xff09;是一种基于Transformer的目标检测模型&#xff0c;由Facebook A…

Redis 从入门到精通【进阶篇】之高可用集群(Redis Cluster)详解

文章目录 0. 前言设计目标核心概念 1. 架构设计和原理1.1. 数据分片2. 节点间通信6. 扩容和缩容 2. 总结3. Redis从入门到精通系列文章4. Redis Cluster面试题4.1. Redis Cluster如何进行扩容和缩容&#xff1f;4.2. Redis Cluster如何进行故障转移&#xff1f;4.3. Redis Clus…

【问题分析解决】git添加.gitignore后不生效问题

一&#xff0c;问题现象 在已经提交过的git管理的项目中&#xff0c;新增加一个.gitignore文件&#xff0c;或者修改.gitignore文件之后&#xff0c;新增的内容不生效。 二&#xff0c;问题原因 因为我们误解了.gitignore文件的用途&#xff0c;该文件只能作用于Untracked F…

JDK JRE JVM

JDK JRE JVM JDKJREJVM三者之间的联系三者之间的区别 JDK JDK是用于开发、编译、调试和运行Java应用程序的软件包&#xff0c;包含了Java编程语言的开发工具和Java运行时环境。JDK包括Java编译器&#xff08;javac&#xff09;、Java虚拟机&#xff08;JVM&#xff09;和Java类…

单轴机器人的结构与特点

单轴机器人是由马达驱动的移动平台&#xff0c;由滚珠螺杆和 U型线性滑轨导引构成&#xff0c;其滑座同时为滚珠螺杆的驱动螺帽及线性滑轨的导引滑块&#xff0c;可用半导体、光电、交通运输业、环保节能产业、精密工具机、机械产业、智慧自动化、生技医疗上。 相对于传统的模组…

django使用channels实现webSocket启动失败

问题描述 使用channels启动ASGI结果却是普通启动&#xff0c;如下&#xff1a; Watching for file changes with StatReloader Performing system checks...System check identified no issues (0 silenced). July 15, 2023 - 18:23:49 Django version 4.2, using settings s…

JavaWeb(3)——HTML、CSS、JS 快速入门

一、JavaScript 运算符 • 赋值运算符&#xff08; &#xff09; 赋值运算符执行过程&#xff1f; 将等号右边的值赋予给左边, 要求左边必须是一个容器 出现是为了简化代码, 比如让 let age 18 &#xff0c;age 加 2 怎么写呢 let age 18age 2console.log(age)age * 2con…

javaee jstl表达式

jstl是el表达式的扩展 使用jstl需要添加jar包 package com.test.servlet;import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;import javax.servlet.ServletException; import javax.servlet…

下载编译Chromium

参考&#xff1a;Mac上本地编译Chrome浏览器踩坑笔记&#xff08;2021.02最新&#xff09; - 掘金 For Mac: 一、下载编译工具链&#xff1a;deptool git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git export PATH"$PATH:/Users/yumlu/cod…

什么是DevOps监控以及如何在组织中实施?

如今的软件开发商经常面临两大挑战——快速交付和大规模创新。DevOps通过在软件开发生命周期(SDLC)中引入自动化来开发和交付高质量的软件&#xff0c;从而帮助解决这些挑战。 持续集成(CI)/持续部署&#xff08;CD)是DevOps实践中自动化的关键组件。它可以自动化代码构建、测试…

力扣 1005. K 次取反后最大化的数组和

题目来源&#xff1a;https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/description/ C题解1&#xff1a;最直接的想法就是负的变正的&#xff0c;如果负的元素数量小于k&#xff0c;就挑选绝对值大的负数变正&#xff1b;如果负的元素数量大于k&#xf…

阿里云声音复刻

阿里云声音复刻 个性化人声定制 阿里云个性化人声定制是智能语音交互产品自学习平台下的一部分 使用方式&#xff1a;https://help.aliyun.com/document_detail/456006.html 方式一&#xff1a;控制台界面定制使用方式 方式二&#xff1a;通过OpenAPI定制&#xff1a;在该页…

回归预测 | MATLAB实现基于KELM-Adaboost核极限学习机结合AdaBoost多输入单输出回归预测

回归预测 | MATLAB实现基于KELM-Adaboost核极限学习机结合AdaBoost多输入单输出回归预测 目录 回归预测 | MATLAB实现基于KELM-Adaboost核极限学习机结合AdaBoost多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于KELM-Adaboo…