【2023.3.5】MOOC程序设计与算法
创始人
2024-06-03 07:31:39
0

【2023.3.5】MOOC程序设计与算法笔记

文章目录

  • 【2023.3.5】MOOC程序设计与算法笔记
    • 说明
    • 一、枚举
    • 二、递归
      • 1-汉诺塔问题
      • 2-N皇后问题
      • 3-逆波兰表达式
      • 4、全排列问题
    • 三、二分算法
      • 1-BinarySearch函数
    • 四、分治
      • 1-归并排序
      • 2-快速排序
    • 五、深度优先搜索
      • 1-基本模型-通用套路
      • 2-迷宫问题
        • (1)基于**递归**的写法
        • (2)基于**堆栈**的写法
    • 六、广度优先搜索BFS
      • 0-quene队列的使用
      • 1-洛谷P1162 填涂颜色
      • 2-洛谷P1443 马的遍历

说明

学习视频:MOOC:程序设计与算法(二)算法基础

做的一些笔记。

一、枚举

二、递归

1-汉诺塔问题

#includeint k=0;
//汉诺塔问题,n代表原始盘子数,原始盘为src,mid作为中转盘,dest作为目标盘
void Hanoi(int n, char src, char mid, char dest) {if (n == 1)printf("%d: %c->%c\n",++k, src, dest);else {Hanoi(n - 1, src, dest, mid);printf("%d: %c->%c\n",++k, src, dest);Hanoi(n - 1, mid, src, dest);}}
int main() {int n;printf("input n:");scanf("%d", &n);Hanoi(n, 'A', 'B', 'C');return 0;
}

2-N皇后问题

N皇后问题是一个经典的问题,在一个N*N的棋盘上放置N个皇后,每行一个并使其不能互相攻击(同一行、同一列、同一斜线上的皇后都会自动攻击)。

#include
#includeint queenPos[50] = { 0 };
int N;//N个皇后
int num = 0;//num种摆法。//在0~k-1个皇后已经摆好的情况下,摆放第k个及以后的皇后
void Nqueen(int k);void printQueenPos(int* queenPos, int k);int main() {printf("input n:");scanf("%d", &N);Nqueen(0);return 0;
}void printQueenPos(int* queenPos, int k) {printf("---------- %d  ---\n",++num);for (int i = 0; i < k; i++) {//打印步骤printf("%d ", queenPos[i]);}putchar('\n');putchar('\n');//制图for (int i = 0; i < k; i++) {for (int j = 0; j < k; j++) {if (j  == queenPos[i])putchar('*');elseputchar('O');putchar(' ');}putchar('\n');}putchar('\n');
}//在0~k-1个皇后已经摆好的情况下,摆放第k个及以后的皇后
void Nqueen(int k) {int i;if (k == N) {printQueenPos(queenPos, k);}//逐步尝试第k个皇后的位置,摆在k行第i列for (i = 0; i < N; i++) {//遍历已经拜访的位置,看是否合理int j;for (j = 0; j < k; j++) {//两皇后成对角线关联,则他们的 行差的绝对值 == 列差的绝对值if (i == queenPos[j] || abs(j - k) == abs(i - queenPos[j])) {//此时表示该摆法不合理break;}}if (j == k) {//此时表示 该摆法合理queenPos[k] = i;Nqueen(k + 1);}}}

3-逆波兰表达式

定义:

image-20230303101755748

测试样例:

代码:

#include
#include//读入一个逆波兰表达式,并计算其值。
double exp() {char s[20];scanf("%s", s);switch (s[0]){case '+':return exp() + exp();case '-':return exp() - exp();case '*':return exp() * exp();case '/':return exp() / exp();default:return atof(s);}
}int main() {int n;printf("input:");printf("%lf\n", exp());return 0;
}

4、全排列问题

#include
#define Max 20int ans[Max] = { 0 };//记录答案
int n;//表示n的全排列
int Visit[Max] = { 0 };//记录是否排列,Visit[k]表示k已排列
int k = 0;//记录全排列的数量void dfs(int step);//step表示dfs递归的层数,即深度优先搜索的步数
void PrintAns(int* ans, int n);//打印答案int main()
{printf("Please input n:");scanf("%d", &n);dfs(1);printf("Total K:%d", k);return 0;
}void dfs(int step) {if (step > n) {PrintAns(ans , n);k++;return;}for (int i = 1; i <= n; i++) {//表示没有排过序if (!Visit[i]) {Visit[i] = 1;ans[step - 1] = i;dfs(step + 1);Visit[i] = 0;ans[step - 1] = 0;}}}void PrintAns(int* ans, int n) {for(int i=0;i

三、二分算法

1-BinarySearch函数

#include
//在包含size个元素的、从小到大排序的int数组a里查早元素p。
//如果找到,则返回元素下标。否则返回-1。复杂度O(log(n))
int BinarySeach(int a[], int size, int p) {int L = 0;int R = size - 1;while (L <= R) {int mid = L + (R - L) / 2;if (a[mid] == p) {return mid;}if (a[mid] > p)R = mid - 1;elseL = mid + 1;}return -1;
}int main() {int a[] = { 0,1,3,4,6,7,9,11,15,18 };int n;printf("input:");scanf("%d", &n);int i = BinarySeach(a, 10, n);printf("a[%d]=%d\n",i, a[i] );return 0;
}

四、分治

把一个任务分成形式与原任务相同、规模更小的多个任务,分别完成。

1-归并排序

一般用递归实现。

菜鸟教程:归并排序:含动图解释。

#include
#includevoid MergeSort(int* a, int n);
void Merge(int* a,  int mid, int end);int main() {int a[100] = { 2,4,5,8,1,14,9,12,15,33,3 ,44,22,11,33};int len = 0;for (len = 0; a[len]; len++);printf("%d\n", len);MergeSort(a, len);for (int i = 0; i < len; i++)printf("%d ", a[i]);
}void MergeSort(int* a, int n) {if (n <= 1) {return;}MergeSort(a, n / 2);MergeSort(a + n / 2, n - n / 2);Merge(a,  n / 2, n  );}
void Merge(int* a,  int mid, int end) {int* b = (int* )malloc(end*sizeof(int));int i = 0, j = mid;int k = 0;while (i < mid && j < end) {if (a[i] < a[j]) {b[k++] = a[i++];}else {b[k++] = a[j++];}}while (i < mid) {b[k++] = a[i++];}while (j < end) {b[k++] = a[j++];}for (i = 0; i < k; i++)a[i] = b[i];free(b);
}

2-快速排序

image-20230303211234661

i 和 j 同时往中间移动。

image-20230303211247746

快速排序

#include
#includevoid QuickSort(int* a, int n);
void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}int main() {int a[100] = { 22,11,33,2,4,5,8,1,14,9,12,15,55,3 ,44};int len = 0;for (len = 0; a[len]; len++);printf("%d\n", len);QuickSort(a, len);for (int i = 0; i < len; i++)printf("%d ", a[i]);
}void QuickSort(int* a, int n) {if (n <= 1)return;int k = a[0];int i = 0, j = n - 1;while (i != j) {while (i < j) {if (a[j] >= k)j--;else {swap(a + i, a + j);break;}}while (i < j) {if (a[i] <= k) {i++;}else {swap(a + i, a + j);break;}}		}//printf("i=%d,j=%d\n", i, j);//重点:此时再将i左边和右边分开快速排序,所以要减一加一,避开第i个。QuickSort(a , i);QuickSort(a + i + 1, n - i-1);
}

五、深度优先搜索

1-基本模型-通用套路

深度优先搜索dfs基本模型-通用套路:摘自:深度优先搜索DFS-C语言实现、思路/解析-简笔

void dfs(step)
{/*1.判断边界,判断本阶段的DFS是否已经结束了*/if(foo == bar){/*Do something*/return ;}/*2.尝试每一种可能,类似于走迷宫中的在每一个点尝试每个方向*/for(i=0;i<_MAX_;++i){do_something();dfs(step+1);//进行下一步undo_something();}return ;
}

2-迷宫问题

已知迷宫地图,输出迷宫的路程解和步数。

//10*10迷宫地图
//S表示起点,E表示出口,#表示墙,O表示路
//该地图有两个解
char map[N + 1][N + 1] = {{"SO##OOO###"},{"#OOOO#OOO#"},{"#O##O###O#"},{"OOO#OO##O#"},{"O#O##OO###"},{"O#####O###"},{"O#OOOOO###"},{"OOO#O#####"},{"###OOO#OOE"},{"##OO#OOO##"},
}; 

通过dfs跑出迷宫答案

dfs,深度优先搜索,就是从一个节点一直往深处搜索,直到走到尽头,再往回走,走下一个节点,再次深搜……就相当于来回遍历,一个人走迷宫。

是基于回溯的思想。而回溯就是基于栈结构。

所以有两种写法,一种是直接递归,一种是自己构造堆栈、压栈出栈。

(1)基于递归的写法

不过递归调用,本就是由系统的堆栈支持的。所以也算堆栈结构。

不用自己实现堆栈,实现起来肯定要简单些。

#include
#define Max 50
#define MapN 10//表示N*N迷宫/*该地图唯一解 
//10*10迷宫地图,S表示起点,E表示出口,#表示墙,O表示路
char map[N+1][N+1] = {{"SO##OOO###"},{"#OOOO#OOO#"},{"#O##O###O#"},{"#OO#OO##O#"},{"O#O##OO###"},{"O#####O###"},{"O#OOOOO###"},{"OOO#O#####"},{"###OOO#OOE"},{"##OO#OOO##"},
};*///10*10迷宫地图,S表示起点,E表示出口,#表示墙,O表示路
//该地图有两个解
char map[MapN + 1][MapN + 1] = {{"SO##OOO###"},{"#OOOO#OOO#"},{"#O##O###O#"},{"OOO#OO##O#"},{"O#O##OO###"},{"O#####O###"},{"O#OOOOO###"},{"OOO#O#####"},{"###OOO#OOE"},{"##OO#OOO##"},
}; int Visit[Max][Max] = { 0 };void dfs(int x, int y, int step);
void PrintAns(int Ans[Max][Max], int step);int main() {int startX = 0, startY = 0, step = 0;Visit[startX][startY] = 1;dfs(startX, startY, step);return 0;
}void dfs(int x, int y, int step) {if (map[x][y] == 'E') {PrintAns(Visit, step);return;}for (int i = 0; i < 4; i++) {int NextX = x, NextY = y;switch (i){case 0:NextX += 1; break;case 1:NextX -= 1; break;case 2:NextY += 1; break;case 3:NextY -= 1; break;}if (NextX >= 0 && NextX < MapN && NextY >= 0 && NextY < MapN) {if (map[NextX][NextY] != '#' && Visit[NextX][NextY] != 1) {Visit[NextX][NextY] = 1;dfs(NextX, NextY, step + 1);Visit[NextX][NextY] = 0;}}}}void PrintAns(int Ans[Max][Max], int step) {for (int i = 0; i < MapN; i++) {for (int j = 0; j < MapN; j++) {if (Ans[i][j]) {putchar('*');}else {putchar(' ');}}putchar('\n');}printf("Total Steps:%d\n", step);putchar('\n');}

(2)基于堆栈的写法

基于堆栈结构的写法,(我不大熟悉,尝试着写,写得不好)

后面才知道,c++有现成的stack容器,用于使用堆栈这种数据结构,不用我们自己写压栈、出栈这些函数,

使用教程参考:C语言-stack的应用

#include
#include
#define Max 50
#define MapN 10//表示N*N迷宫//10*10迷宫地图,S表示起点,E表示出口,#表示墙,O表示路
//该地图有两个解
char map[MapN + 1][MapN + 1] = {{"SO##OOO###"},{"#OOOO#OOO#"},{"#O##O###O#"},{"OOO#OO##O#"},{"O#O##OO###"},{"O#####O###"},{"O#OOOOO###"},{"OOO#O#####"},{"###OOO#OOE"},{"##OO#OOO##"},
}; struct StepInStatk {int x;int y;int k;//记录已走过的上下左右,0~3,4表示所有方向已走过int step;//第多少步。StepInStatk* pNext;
};int Visit[Max][Max] = { 0 };//记录改坐标是否已走过。void dfsByStack(StepInStatk* pFirstStep,int step);
void PrintAns(StepInStatk* pStackTop);
StepInStatk* InitStep(int x,int y);//初始化迷宫的起始位置
StepInStatk* PushStepStack(StepInStatk* pStackTop, int x,int y);//压栈
StepInStatk* PopStepStack(StepInStatk* pStackTop);//出栈int main() {int startX = 0, startY = 0;StepInStatk* pFirstStep = InitStep(startX, startY);Visit[startX][startY] = 1;dfsByStack(pFirstStep, 0);return 0;
}void dfsByStack(StepInStatk* pFirstStep, int step) {StepInStatk* pStackTop = pFirstStep;while (1) {int i;for (i = pStackTop->k; i < 4; i++) {int NextX = pStackTop->x;int NextY = pStackTop->y;switch (i){case 0:NextX += 1; break;case 1:NextX -= 1; break;case 2:NextY += 1; break;case 3:NextY -= 1; break;}if (NextX >= 0 && NextX < MapN && NextY >= 0 && NextY < MapN) {if (Visit[NextX][NextY] == 0 && map[NextX][NextY] != '#') {Visit[NextX][NextY] = 1;//标记这个位置已走过。pStackTop->k = i + 1;//迷宫的走法上下左右,k表示下一次应走的方向,k=4时表示4个方向皆走过了。pStackTop = PushStepStack(pStackTop, NextX, NextY);break;}}}if (map[pStackTop->x][pStackTop->y] == 'E') {//找到出口PrintAns(pStackTop);Visit[pStackTop->x][pStackTop->y] = 0;pStackTop = PopStepStack(pStackTop);}else if (i == 4) {//表示该节点的四个方向都已经走过了,已无路可走,需要回溯。Visit[pStackTop->x][pStackTop->y] = 0;pStackTop = PopStepStack(pStackTop);}if (pStackTop == NULL)//只有当栈底,也就是第一个起始节点的四个方向都遍历完,才会pop出栈,使pStackTop指向NULL。break;}
}StepInStatk* InitStep(int x, int y) {StepInStatk* pFirstStep = (StepInStatk*)malloc(sizeof(StepInStatk));pFirstStep->x = x;pFirstStep->y = y;pFirstStep->k = 0;pFirstStep->step = 0;pFirstStep->pNext = NULL;return pFirstStep;
}StepInStatk* PushStepStack(StepInStatk* pStackTop, int x, int y) {StepInStatk* pStep = (StepInStatk*)malloc(sizeof(StepInStatk));pStep->x = x;pStep->y = y;pStep->k = 0;pStep->step = pStackTop->step + 1;pStep->pNext = pStackTop;return pStep;
}
StepInStatk* PopStepStack(StepInStatk* pStackTop) {return pStackTop->pNext;
}void PrintAns(StepInStatk* pStackTop) {StepInStatk* pStep = pStackTop;int Ans[MapN+1][MapN+1] = { 0 };int step = pStackTop->step;while (pStep != NULL) {Ans[pStep->x][pStep->y] = 1;pStep = pStep->pNext;}for (int i = 0; i < MapN; i++) {for (int j = 0; j < MapN; j++) {if (Ans[i][j]) {putchar('*');}else {putchar(' ');}}putchar('\n');}printf("Total Steps:%d\n", step);putchar('\n');}

六、广度优先搜索BFS

广度优先算法,基于队列的数据结构。

学习视频:B站:洛谷 普及组试炼场 - 广度优先搜索 (BFS)

0-quene队列的使用

使用队列数据结构,c++里有现成的容器queue。

queue的使用案例:C语言-队列(queue)的应用

#include 
#include 
using namespace std;int main(){queue q;for(int i = 0; i < 5; i++){q.push(i);cout << "成功将" << i << "入队" << endl;}cout << endl;while(!q.empty()){cout << "当前队首:" << q.front() << "\t当前队尾:" << q.back();cout << "\t当前队列大小:" << q.size() << endl;q.pop();}return 0;
}

1-洛谷P1162 填涂颜色

洛谷:P1162 填涂颜色

#include 
#include 
using namespace std;struct location {int x;int y;
};
int xx[] = { 1,0,-1,0 };
int yy[] = { 0,1,0,-1 };
int aa[40][40] = { 0 };
int visit[40][40] = { 0 };
int main() {int n = 0;cin >> n;for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {cin >> aa[i][j];}}queue queue;location Temp = { 0,0 };queue.push(Temp);visit[0][0] = 1;while (!queue.empty()) {for (int i = 0; i < 4; i++) {int dx = queue.front().x + xx[i];int dy = queue.front().y + yy[i];if (dx >= 0 && dx <= n + 1 && dy >= 0 && dy <= n + 1) {if (visit[dx][dy] == 0 && aa[dx][dy] == 0) {visit[dx][dy] = 1;Temp.x = dx;Temp.y = dy;queue.push(Temp);}}}queue.pop();}for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (visit[i][j] == 1 || aa[i][j] == 1) {cout << aa[i][j] << " ";}else {cout << "2 ";}}cout << endl;}return 0;
}

2-洛谷P1443 马的遍历

洛谷:P1443 马的遍历

#include 
#include 
using namespace std;struct location {int x;int y;int s;//表示步数,第几步
};
int xx[] = { 1, 1, 2, 2,-1,-1,-2,-2};
int yy[] = { 2,-2, 1,-1, 2,-2, 1,-1};
int map[402][402] = { -1 };
int visit[402][402] = { 0 };
int main() {int n, m, x, y;cin >> n >> m >> x >> y;//全部置为-1,表示这些点没有访问过。for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {visit[i][j] = -1;}}queue queue;visit[x][y] = 0;queue.push( { x, y, 0 });//这样push也是一个结构体数据。while (!queue.empty()) {for (int i = 0; i < 8; i++) {int dx = queue.front().x + xx[i];int dy = queue.front().y + yy[i];if (dx >= 1 && dy >= 1 && dx <= n && dy <= m) {if (visit[dx][dy] == -1) {location temp = { x,y,0 };temp.x = dx;temp.y = dy;temp.s = queue.front().s + 1;//BFS的特性,其队列首部和尾部的一定是相邻步骤数,相差为1.queue.push(temp);visit[dx][dy] = temp.s;//记录马访问该点时的步骤数量。}}}queue.pop();}for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {cout << visit[i][j] << ' ';}cout << endl;}return 0;
}

相关内容

热门资讯

122.(leaflet篇)l... 听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行...
育碧GDC2018程序化大世界... 1.传统手动绘制森林的问题 采用手动绘制的方法的话,每次迭代地形都要手动再绘制森林。这...
育碧GDC2018程序化大世界... 1.传统手动绘制森林的问题 采用手动绘制的方法的话,每次迭代地形都要手动再绘制森林。这...
Vue使用pdf-lib为文件... 之前也写过两篇预览pdf的,但是没有加水印,这是链接:Vu...
PyQt5数据库开发1 4.1... 文章目录 前言 步骤/方法 1 使用windows身份登录 2 启用混合登录模式 3 允许远程连接服...
Android studio ... 解决 Android studio 出现“The emulator process for AVD ...
Linux基础命令大全(上) ♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维...
再谈解决“因为文件包含病毒或潜... 前面出了一篇博文专门来解决“因为文件包含病毒或潜在的垃圾软件”的问题,其中第二种方法有...
南京邮电大学通达学院2023c... 题目展示 一.问题描述 实验题目1 定义一个学生类,其中包括如下内容: (1)私有数据成员 ①年龄 ...
PageObject 六大原则 PageObject六大原则: 1.封装服务的方法 2.不要暴露页面的细节 3.通过r...
【Linux网络编程】01:S... Socket多进程 OVERVIEWSocket多进程1.Server2.Client3.bug&...
数据结构刷题(二十五):122... 1.122. 买卖股票的最佳时机 II思路:贪心。把利润分解为每天为单位的维度,然后收...
浏览器事件循环 事件循环 浏览器的进程模型 何为进程? 程序运行需要有它自己专属的内存空间࿰...
8个免费图片/照片压缩工具帮您... 继续查看一些最好的图像压缩工具,以提升用户体验和存储空间以及网站使用支持。 无数图像压...
计算机二级Python备考(2... 目录  一、选择题 1.在Python语言中: 2.知识点 二、基本操作题 1. j...
端电压 相电压 线电压 记得刚接触矢量控制的时候,拿到板子,就赶紧去测各种波形,结...
如何使用Python检测和识别... 车牌检测与识别技术用途广泛,可以用于道路系统、无票停车场、车辆门禁等。这项技术结合了计...
带环链表详解 目录 一、什么是环形链表 二、判断是否为环形链表 2.1 具体题目 2.2 具体思路 2.3 思路的...
【C语言进阶:刨根究底字符串函... 本节重点内容: 深入理解strcpy函数的使用学会strcpy函数的模拟实现⚡strc...
Django web开发(一)... 文章目录前端开发1.快速开发网站2.标签2.1 编码2.2 title2.3 标题2.4 div和s...