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

目录

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.hqwc.cn/news/28529.html

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

相关文章

如何在Windows中将任务导入任务计划程序

任务计划程序使你能够在选定的计算机上自动执行例行任务。任务调度程序通过监视你选择的启动任务的任何条件&#xff08;称为触发器&#xff09;&#xff0c;然后在满足条件时执行任务来实现这一点。 你可以导入导出的任务&#xff0c;这将把导入的任务添加到任务文件夹中&…

复习java基础

复习一天有点忘了的知识&#xff1a; 结构化编程 结构化程式设计(英语:Structured programming)是1960年代开始发展起来的一种编程典范。它采用子程序、程式码区块、for循环以及while循环等结构来取代传统的goto。 指导思想 自顶向下、逐步求精、模块化 编程过程 流程图是…

SOMEIP协议----第一节(概述)

SOMEIP协议 概述 1.什么是SOME/IP? SOME/IP: 如上图所述,连起来就是基于车载以太网技术的面向服务的可扩展中间件 汽车某ECU软件算法如果需要和其他ECU交互,大部分都通过跨ECU之间的服务来实现,即可以通过车载以太网异步调用其他ECU上的服务,应用开发者只需要关注服务…

Linux下安装Mysql (CentOS 7) 详解

文章目录 前言环境检查查看是否安装MySql查看系统版本 源安装安装mysql的yum源官网下载从windows上传到linuxrz命令 方法2&#xff1a; 安装Mysql常见错误密钥问题安装后查看mysql是否可以工作查看是否安装成功启动服务 登录mysql配置文件方法&#xff08;免密码&#xff09; 使…

【ARM Cortex-M 系列 1 -- Cortex-M0, M3, M4, M7, M33 差异】

文章目录 Cortex-M 系列介绍Cortex-M0/M0 介绍Cortex-M3/M4 介绍Cortex-M7 介绍Cotex-M33 介绍 下篇文章&#xff1a;ARM Cortex-M 系列 2 – CPU 之 Cortex-M7 介绍 Cortex-M 系列介绍 Cortex-M0/M0 介绍 Cortex-M0 是 ARM 公司推出的一款微控制器&#xff08;MCU&#xff0…

http连接处理(下)(四)

1.结合代码分析请求报文响应 下面我们将介绍服务器如何响应请求报文&#xff0c;并将该报文发送给浏览器端。首先介绍一些基础API&#xff0c;然后结合流程图和代码对服务器响应请求报文进行详解。 基础API部分&#xff0c;介绍stat、mmap、iovec、writev。 流程图部分&…

go语言中的string类型简介

在 Go 中&#xff0c;String 是一种不可变的类型&#xff0c;不能被修改。 在 Go 语言中&#xff0c;字符串由 Unicode 字符组成&#xff0c;每个字符都可以用一个或多个字节来表示。我们使用双引号或反引号来定义字符串&#xff0c;使用反引号定义的字符串不会对其内容进行任何…

win7,win10下删除HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\报错

在调试虚拟网卡驱动时&#xff0c;由于修改错误&#xff0c;导致枚举顺序错乱&#xff0c;因此通过删除HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\Root\WINTUN下的所有项&#xff0c;即可&#xff0c;win10可用。 1、下载PStools&#xff1a; http://technet.microsoft.c…

(学习笔记-TCP基础知识)TCP与UDP区别

UDP UDP不提供复杂的控制机制&#xff0c;利用IP提供面向[无连接]的通信服务。 UDP协议非常简单&#xff0c;头部只有8个字节(位)&#xff0c;UDP的头部格式如下&#xff1a; 目标和源端口&#xff1a;主要是告诉UDP协议应该把报文发给哪个进程包长度&#xff1a;该字段保存了…

行为式验证码(成语点选)(C#版和Java版)

一、先看效果图 二、背景介绍 图形验证码网上有挺多&#xff0c;比如&#xff1a;网易易盾、腾讯防水墙、阿里云验证码等等。参考了一下&#xff0c;自己实现了一个简单的成语点选的模式。 三、实现思路 1.选择若干张图片&#xff08;这里使用的是320x160的尺寸&#xff09;…

HTPP入门教程||HTTP 状态码||HTTP content-type

HTTP 状态码 当浏览者访问一个网页时&#xff0c;浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前&#xff0c;此网页所在的服务器会返回一个包含 HTTP 状态码的信息头&#xff08;server header&#xff09;用以响应浏览器的请求。 HTTP 状态码的英文为…

Nacos服务注册和配置中心(Config,Eureka,Bus)2

Nacos数据模型 Nacos领域模型,Namespace命名空间、Group分组、集群这些都是为了进行归类管理&#xff0c;把服务和配置文件进行归类&#xff0c;归类之后就可以实现一定的效果&#xff0c;比如隔离。对于服务来说&#xff0c;不同命名空间中的服务不能够互相访问调用 N…