【笔记】数据结构——8月27日

news/2024/9/18 22:55:23/ 标签: 数据结构, 笔记, 算法

@toc

静态链表

静态链表的存储结构

#define maxn 15struct space
{int cur;int key; 
}s[maxn];int LocateElem_SL(SLinkList *s,ElemType e)
{//在静态链表中查找第一个值为e的元素//若找到,则返回它在链表中的位置,否则返回0 i=s[0].cur;while(i&&s[i].data!=e)i=s[i].cur;return i;
} 

集合(A-B)∪(B-A)

#include<stdio.h>#define MAXSIZE 15struct space
{int cur;int key; 
}s[MAXSIZE];void InitSpace_SL(struct space *s)
{
//space[cur]为头指针,0表示空指针
//space中各分量链成一个备用链表
//s[0].cur为头指针int i;for(i=0;i<MAXSIZE-1;i++)s[i].cur=i+1; s[MAXSIZE-1].cur=0;
}int Malloc_SL(struct space *s)
{
//分配空间,若备用空间链表非空,返回分配的节点下标int	i=s[0].cur;if(i)s[0].cur=s[i].cur;return i;
} void free_SL(struct space *s,int k)//将下标为k的空闲节点回收到备用链表 
{s[k].cur=s[0].cur;s[0].cur=k;
}void PrintSpace_SL(struct space *s)
{int i;for(i=s[1].cur;i!=0;i=s[i].cur)//第一个里面不存东西 printf("%d ",s[i].key);printf("\n");
}void different(struct space *s)
{InitSpace_SL(s);int head=Malloc_SL(s);int last=head;int i,j,k;int m,n;scanf("%d%d",&m,&n);//输入集合A和集合B的元素的个数for(j=1;j<=m;j++)//建立集合A的链表 {i=Malloc_SL(s);//分配节点 scanf("%d",&s[i].key);s[last].cur=i;//插入表尾 last=i; } s[last].cur=0;//尾结点的指针为空//PrintSpace_SL(s);int b;for(j=1;j<=n;j++){//依次输入B的元素,若不在当前表中,则插入,否则删除scanf("%d",&b);int p=head;k=s[head].cur;//k指向集合A中的第一个结点。while(k&&s[k].key!=b)//在当前表中查找{p=k;k=s[k].cur;}if(k==space[last].cur)//当前表中不存在该元素,插入last所在节点之后,且last的位置不变{i=Malloc_SL(s);s[i].key=b;s[i].cur=0;s[last].cur=i;last=i;}else{s[p].cur=s[k].cur;free_SL(s,k);if(last==k)r=p;//如果删除的是last所指向的结点,则需修改为节点。}} 
}int main()
{different(s);PrintSpace_SL(s);return 0;
}

在终端输入集合元素,先建立表示集合A的静态链表S,然后输入集合B的元素,同时查找S表。若存在和B相同的元素,则从S表中删除,否则将此元素插入S中。

代码参考了社区的da1234cao

行编辑程序

接受用户从终端输入的程序或数据,并存入用户的数据区。由于用户在终端上输入的时,不能保证不出差错。

  1. “每接收一个字符即存入用户数据区”的做法显然不是最恰当的。
  2. 较好的做法是设立一个输入缓冲区,接收一行的字符,逐行存入用户数据区。当用户发现刚刚键入一个字符是错的,可以补进一个退格符“#”表示前一个字符无效。同样的退行符“@”
    【使用栈进行判别的方法】
void LineEdit(){
//利用字符栈S,从终端接受一行并传送至调用过程的数据区。
InitStack(S);
ch=getchar();while(ch!=EOF){while(ch!=EOF&&ch!='\n'){switch(ch){case '#':Pop(S,c);break;//仅当非空栈的退栈case '@':ClearStack(S);break;//重置S为空栈default: Push(S,ch);break;//有效字符进栈,未考虑栈满情形}ch=getchar();//接收下一个字符	}//将从栈底到栈顶的栈内字符传送至调用过程的数据区ClearStack(S);if(ch!=EOF)ch=getchar();}DestroyStack(S);
}//LineEdit

迷宫求解

求迷宫中从入口到出口的所有路径,从入口,顺着某一方向能走通则继续前进,否则沿原路返回,换一个方向再继续探索,直至所有可能的通路都探索到为止。为了保证在任何位置上都能沿原路退回,需要用到栈。
栈+回溯法
在这里插入图片描述
在这里插入图片描述
2.方向的定义
可以根据迷宫的入口和出口大致方向去决定优先方向,这里的迷宫入口在出口的西北方向,那么优先的方向我依次为东、南、西、北,也就是说优先往东走,其次是南、西、北。方向的移动可以根据当前坐标进行上下左右的移动,只需要去定义一个方向数组,然后加上这个数组的方向即可。
在这里插入图片描述
在这里插入图片描述

int maze[6][6] = {{1,1,1,1,1,1},{1,0,0,1,1,1},{1,0,0,0,0,0},{1,0,1,1,1,0},{1,0,0,0,0,1},{1,1,1,1,1,1}};//试探方向存储结构
typedef struct {int xx, yy;
}Direction;
//东南西北
Direction dire[4] = { {0,1},{1,0},{0,-1},{-1,0} };

走迷宫代码

走迷宫的代码逻辑
**参考严蔚敏的《数据结构

设当前位置的初值为[入口位置];
do{if(当前位置可通){将当前位置cur插入栈顶;//纳入路径if(当前位置是[出口位置]),则结束;//求得路径存放在栈中else 切换当前位置的东邻方块为新的当前位置}else{if(栈不空且栈顶位置尚有其他方向未探索) 设定新的当前位置为沿顺时针方向旋转找到的栈顶位置的下一相邻块//endifif(栈不空但栈顶位置的四周均不可通){删去栈顶位置;if(栈不空),则重新测试新的栈顶位置,直至找到一个可通的相邻块或出栈至栈空}//endif}//endelse
}(栈不空)
#include<stdio.h>
#include<assert.h>
#include"stack.h"//试探方向存储结构
typedef struct {int xx, yy;
}Direction;
//东南西北
Direction dire[4] = { {0,1},{1,0},{0,-1},{-1,0} };//判断能不能走出去,路径放入到了栈里面去//⭐⭐⭐重点代码
bool Findpath(int maze[][6],Stack* stack ,Direction dir[],int startx,int starty,int endx,int endy) {//startx,starty是起点的坐标;endx、endy是终点的坐标.assert(stack);int x, y, di;int line, col;//初始化maze[startx][starty] = -1;ElemType start = { startx,starty,-1 };push(stack, start);while (!isEmpty(stack)) {Node* po = pop(stack);ElemType temp = po->data;x = temp.x;y = temp.y;di = temp.di++;//使得栈储存了一条通路while (di < 4) {line = x + dire[di].xx;col = y + dire[di].yy;if (maze[line][col] == 0) {//储存上一个节点的位置,入栈temp = { x,y,di };push(stack, temp);x = line;y = col;maze[line][col] = -1;if (x == endx && y == endy) {//把终点的位置入栈temp = { x,y,-1 };push(stack, temp);return true;}elsedi = 0;}elsedi++;}}return false;
}int main() {int maze[6][6] = {{1,1,1,1,1,1},{1,0,0,1,1,1},{1,0,0,0,0,0},{1,0,1,1,1,0},{1,0,0,0,0,1},{1,1,1,1,1,1}};Stack stack;stack_init(&stack);printf("能否出去:%d\n", Findpath(maze, &stack, dire, 1, 1, 4, 4));show_path(stack.point);//输出遍历的结果
}

栈的cpp代码:

#include<stdio.h>
#include<stdlib.h>//数据类型
typedef struct datatype {int x, y, di;
}ElemType;
//节点
typedef struct node {ElemType data;struct node* next;
}Node;
//栈顶指示
typedef struct stack {int count;	//计数Node* point;
}Stack;//创建节点
Node* create_node(ElemType data) {Node* new_node = (Node*)malloc(sizeof(Node));if (new_node) {new_node->data = data;new_node->next = NULL;return new_node;}else{printf("ERROR\n");}
}//初始化
void stack_init(Stack* top) {top->count = 0;top->point = NULL;
}int isEmpty(Stack* top) {if (top->count == 0) {return 1;}return 0;
}//入栈
void push(Stack* top, ElemType data) {Node* new_node = create_node(data);if (new_node) {top->count++;if (top->count == 1) {//如果入栈是第一个节点的话top->point = new_node;}else{new_node->next = top->point;top->point = new_node;}}elsereturn;
}//出栈
Node* pop(Stack* top) {Node* pop_node = NULL;if (!isEmpty(top)) {pop_node = top->point;top->point = pop_node->next;top->count--;}return pop_node;
}//递归输出路径
void show_path(Node* node) {if (!node)return;show_path(node->next);printf("(%d,%d)\n", node->data.x, node->data.y);
}

栈的头文件h代码

#pragma once
//链表栈
//数据类型
typedef struct datatype {int x, y, di;
}ElemType;
//节点
typedef struct node {ElemType data;struct node* next;
}Node;
//栈顶指示
typedef struct stack {int count;	//计数Node* point;
}Stack;void stack_init(Stack* top);
int isEmpty(Stack* top);
void push(Stack* top, ElemType data);
Node* pop(Stack* top);
void show_path(Node* node);

部分文字参考
Fitz&

递归

  1. 递归的数学函数
  2. 拥有递归特性的数据结构:二叉树,广义表
  3. 可递归求解的问题:八皇后 hanoi塔

被调用函数和调用函数的栈关系

【信息传递】和【控制转移】都通过栈进行
系统将整个程序运行时所需的【数据空间】都安排在栈中
当前运行程序数据区在【栈顶】

运行被调用函数之前,系统需要完成3件事
A调用B
A:调用函数
B:被调用函数
1)将所有的实在参数、返回地址等信息传递给被调用函数保存
2)为被调用函数的局部变量分配存储区
3)将控制转移到被调函数的入口。
而从被调用函数返回调用函数之前完成3件事情。
1)保存被调用函数的计算结果
2)释放被调用函数的数据区
3)依照被调用函数保存的返回地址将控制转移到调用函数

队列

队头队尾

  1. 操作系统作业排队
    运行结果都需要通过通道输出,就要按请求输出的先后次序排序
    通道传输完毕可以接受新的输出任务,队头作业先从队列中退出作输出操作。申请输出的作业都从队尾进入队列。

链队列

插入和删除需要修改尾指针和头指针
一般删除队列头元素,仅需修改队头结点的指针,但【删除最后一个元素】的时候,队列尾指针需要重新赋值指向头结点。

队列尾指针指向队列尾元素的下一个位置【是空的】
单纯的带尾指针的单链表/循环链表 尾指针指向最后一个结点。【不空】

[循环队列]两种判空和判满的方法

  1. 另设一个标志位区别队列空还是满
  2. 少用一个元素空间 约定以“队列头指针在队列尾指针的下一位置”作文队列呈满的状态

  1. 串的定长顺序存储表示
#define MAXSTRLEN 255
typedef unsigned char SString[MAXSTRLEN+1]
  • 串的长度表示
    • 0的数组分量存放串的实际长度
    • 串值后面加上一个不计入串长的结束标志“\0”
  1. 串的堆存储表示
    动态分配串的大小,且具有顺序存储的特点
typedef struct{
char *ch;
int length;
}
⭐
T.ch = (char*)malloc((s1.length+s2.length)*sizeof(char))
free(T.ch)
  1. 串的块链存储表示[存储占用量大]
typedef struct Chunk{
char ch[CHUNKSIZE];
struct Chunk *next;
}Chunk;
typedef struct{Chunk *head,*tail;int curlen;
}LString;
串操作实例
  1. 文本编辑
    实质是修改字符数据的形式或格式,串的查找删除插入
    用户可以利用换行符和换页符将文本划分成若干页,每页有若干行
    文本看成一个字符串,页是文本串的子串,行是页的子串
  1. 需要建立行表和页表
    行号/页号,起始地址,长度
  1. 建立词索引表
    书名关键字索引,折半查找,顺序混出
    索引项:关键词,书号索引

数组和广义表

  1. 稀疏矩阵
  2. 广义表
    通常采用链式存储结构,列表中的数据元素可能为原子或列表
    需要两种结构的节点:表结点 原子节点
typdef enum{ATOM,LIST}ElemTag;//ATOM=0 原子,LIST=1:子表
typedef struct GLNode{ElemTag tag;//公共部分,用于区分原子和列表union{AtomType atom;//atom是原子结点的值域,AtomType由用户定义struct{struct GLNode *hp,*tp;}ptr ;//ptr表结点的指针域,ptr.hp ptr.tp//ptr.hp可能指向原子节点或表结点//ptr.tp指向列表表尾,除非表尾为空,则指针空,否则必为表节点。}}*GList;

另一种表示方法

typdef enum{ATOM,LIST}ElemTag;//ATOM=0 原子,LIST=1:子表
typedef struct GLNode{ElemTag tag;//公共部分,用于区分原子和列表union{AtomType atom;//atom是原子结点的值域,AtomType由用户定义struct GLNode *hp;}struct GLNODE *tp;//相当于线性链表的下一个元素节点
}*GList;

树和二叉树

树的应用:等级分类(层次结构),数据库,源程序的语法结构,族谱,社会机构
树的结构表示方法:
a. 嵌套集合
b. 广义表
c. 凹入表示法

树的存储结构

  1. 双亲表示法
  2. 孩子表示法
  3. 孩子兄弟表示法 firstchild nextsibling(兄弟节点)

二叉树可以有5种基本形态
空,仅有根,左空,右空,左右非空

二叉树的存储结构

  1. 顺序存储结构(仅适用于完全二叉树)
  2. 链式存储结构
    create方法:【先序次序】输入二叉树中节点的值
    二叉链表:3个数据域,不包括双亲
    三叉链表:4个数据域,包括双亲
    含有n个节点的二叉链表中有n+1个空链域

利用了空链域——线索链表

前缀表达式(波兰式)后缀表达式(逆波兰式)
表达式:二叉树+栈
向下的箭头表示更深一层的递归调用,向上的箭头表示从递归调用退出返回。

先序遍历,中序遍历,后续遍历树林
树与等价问题

等价关系:自反的,对称的,传递的
等价类:
同一等价类的程序变量可被分配到同一存储单位中去。
划分等价类可以用于求网络中的最小生成树等图的算法中。
划分等价类:【使用双亲表示法作为存储结构】
1) 构造只含单个成员的集合
2)判定某个元素所在的子集
3)归并两个互补相交的集合为一个集合

集合可以通过位向量和有序表表示
以集合为基础的抽象数据类型,取决于该集合的大小以及对此集合所进行的操作。



http://www.ppmy.cn/news/1519379.html

相关文章

使用本地IP无法访问前端项目的问题

说明&#xff1a;记录一次使用本机IP无法访问前端项目的问题 场景&解决 前端项目在我本机电脑上部署完成&#xff0c;我想通过局域网的IP把地址发给测试&#xff0c;发现使用localhost和127.0.0.0都能访问到前端项目&#xff0c;但是这个地址只能在自己的电脑上访问。 解…

记一次学习--webshell绕过(利用清洗函数)

目录 样本 样本修改 样本 <?php $a array("t", "system"); shuffle($a); $a[0]($_POST[1]); 通过 shuffle 函数打乱数组,然后通过$a[0]取出第一个元素&#xff0c;打乱后第一个元素可能是t也可能是system。然后再进行POST传参进行命令执行。 这里抓…

使用 Puppeteer 在 PHP 中解决 reCAPTCHA 以进行网页抓取

您是否在抓取数据时遇到 reCAPTCHA 障碍&#xff1f;我也遇到过。这些 CAPTCHA 挑战会将简单的抓取任务变成一大障碍。但别担心&#xff0c;我有一个解决方案可以帮助您轻松绕过这些障碍。 在本博文中&#xff0c;我将引导您使用 Puppeteer&#xff08;一个功能强大的 Node.js…

瑞芯微RK3566开发板USB OTG模式介绍及命令切换,触觉智能EVB3566主板鸿蒙硬件厂商

一、USB OTG的模式 host模式&#xff08;下行&#xff09;&#xff1a;为u盘等设备供电&#xff0c;不可以进行调试&#xff0c;连接adb或者烧录等操作。 device模式&#xff08;上行&#xff09;&#xff1a;可以进行调试&#xff0c;连接adb或者烧录等操作&#xff0c;即US…

基于xr-frame实现微信小程序的人脸识别3D模型叠加AR功能(含源码)

前言 xr-frame是一套小程序官方提供的XR/3D应用解决方案&#xff0c;基于混合方案实现&#xff0c;性能逼近原生、效果好、易用、强扩展、渐进式、遵循小程序开发标准。xr-frame在基础库v2.32.0开始基本稳定&#xff0c;发布为正式版&#xff0c;但仍有一些功能还在开发&#…

商圣集团:数字创新,引领智慧生活新篇章

在全球化经济不断演进的大潮中&#xff0c;数字经济已成为推动社会进步的关键引擎&#xff0c;重塑着我们的生产与生活模式。商圣集团&#xff0c;以服务社会、创新驱动为核心价值观&#xff0c;致力于利用数字化技术&#xff0c;为个人和企业带来高效、便捷的服务体验&#xf…

OpenCV绘图函数(7)从一个椭圆定义中提取出多边形的顶点坐标函数ellipse2Poly()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 近似一个椭圆弧为一个多边形线。 函数 ellipse2Poly 计算近似指定椭圆弧的多边形线的顶点。它被 ellipse 函数所使用。如果 arcStart 大于 arcEn…

自学数据结构的网站

自学数据结构的网站有很多&#xff0c;以下是一些推荐的高质量和受欢迎的网站&#xff1a; LeetCode 描述&#xff1a;LeetCode是一个知名的在线编程训练平台&#xff0c;特别适合算法和数据结构的学习与练习。它提供了大量的编程题目&#xff0c;涵盖了从简单到困难的各个难度…

基于YOLO的车牌检测识别(YOLO+Transformer)

概述&#xff1a; 基于深度学习的车牌识别&#xff0c;其中&#xff0c;车辆检测网络直接使用YOLO侦测。而后&#xff0c;才是使用网络侦测车牌与识别车牌号。 车牌的侦测网络&#xff0c;采用的是resnet18&#xff0c;网络输出检测边框的仿射变换矩阵&#xff0c;可检测任意形…

「bug」nvitop ERROR: Failed to initialize curses

nvitop 作为一个优秀个 Nvidia显卡查询库&#xff0c;简单易用且显示信息十分丰富&#xff0c;相比 Nvidia-smi 更方便&#xff0c;简直是每个 开发人员必备的库&#xff0c;安装也十分方便&#xff0c;直接采用 pip install nvitop 即可&#xff0c;调用的时候也是直接在 Term…

【Python报错已解决】“ModuleNotFoundError: No module named ‘timm‘”

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 引言&#xff1a;一、问题描述1.1 报错示例&#xff1a;当我们尝试导入timm库时&#xff0c;可能会看到以下错误信息。…

k8s sa

在Kubernetes&#xff08;K8S&#xff09;中&#xff0c;SA是Service Account&#xff08;服务账户&#xff09;的简称。Service Account是Kubernetes集群中的一种资源对象&#xff0c;用于识别和验证Pod访问集群中其他资源的身份。以下是关于K8S SA的详细解释&#xff1a; 一、…

JavaScript中将style的String类型转换成Object类型

在React开发中&#xff0c;我们或许经常遇到要将font-size:20px;转换成对象类型{fontSize:"20px"},如下我自己写了个类&#xff0c;正则匹配-后面的第一个字为大写字母&#xff0c;并且去掉-,然后将:后的属性转换为字符串类型&#xff0c;代码如下 function styleSt…

GitLab 是什么?GitLab使用常见问题解答

GitLab 是什么 GitLab是由GitLab Inc.开发&#xff0c;使用MIT许可证的基于网络的Git仓库管理工具开源项目&#xff0c;且具有wiki和issue跟踪功能&#xff0c;使用Git作为代码管理工具&#xff0c;并在此基础上搭建起来的web服务。 ​GitLab 是由 GitLab Inc.开发&#xff0c…

k3s安装部署说明

前言: 为什么不是k8s&#xff0c;k8s机子要求资源太高了&#xff0c;先来个简单的k3s 1:环境 ubuntu18 2安装docker ubuntu18.0.4 如下 1:禁用防火墙及SELinux(可能需要禁止) systemctl stop firewalld && systemctl disable firewalld 2: 开启路由转发 sudo vim /e…

微信小程序:自定义扫码功能

我们今天主要是介绍小程序自定义扫码的应用&#xff0c;相关业务处理可以根据自己需求来填补 WXML&#xff1a; <view class"scan-box direction-column" wx:if"{{ showCanScan }}"><camera class"camera" resolution"high"…

摄像头的ISP和SOC的GPU有区别吗?

摄像头的主芯片必须包含ISP&#xff0c;也就是图像处理器核心。而SOC的GPU或者说显卡也包含图像处理器也就是GPU。两者并无本质区别&#xff0c;都是实现数字图像处理算法。同样的用FPGA做内窥镜图像处理和用FPGA做显示图像处理器本质上也是一样的。 当然两者存在一些细微差别…

【BLE】四.SMP安全配对详解

设备配对流程 SMP专业术语 Paring&#xff08;配对&#xff09;&#xff1a; 配对能力交换&#xff0c;设备认证&#xff0c;密钥生成&#xff0c;连接加密以及机密信息分发等 过程 Bonding&#xff08;绑定&#xff09; 配对中会生成一个长期密钥&#xff08;LTK&#xff0c;…

灾难性遗忘问题(Catastrophic Forgetting,CF)是什么?

灾难性遗忘问题&#xff08;Catastrophic Forgetting&#xff0c;CF&#xff09;是什么&#xff1f; 在深度学习和人工智能领域中&#xff0c;“灾难性遗忘”&#xff08;Catastrophic Forgetting&#xff09;是指当神经网络在增量学习&#xff08;Incremental Learning&#…

使用 Milvus Lite、Llama3 和 LlamaIndex 搭建 RAG 应用

大语言模型&#xff08;LLM&#xff09;已经展示出与人类交互并生成文本响应的卓越能力。这些模型可以执行各种自然语言任务&#xff0c;如翻译、概括、代码生成和信息检索等。 为完成这些任务&#xff0c;LLM 需要基于海量数据进行预训练。在这个过程中&#xff0c;LLM 基于给…