【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;
}

相关内容

热门资讯

电脑安卓系统卡嘛,安卓系统卡顿... 你有没有遇到过这种情况:手机用得正欢,突然间,安卓系统就像老牛拉车一样慢吞吞的,让人抓狂!电脑安卓系...
华为荣耀的安卓系统精简,极致体... 你有没有发现,现在的手机越来越像是一个小型的电脑了?各种功能齐全,操作复杂,有时候用起来还真是让人头...
原生安卓系统手机刷miui,深... 你有没有想过,你的原生安卓系统手机,是不是也能焕发出新的活力呢?没错,今天就要来聊聊这个话题——如何...
车载安卓系统怎么装carpla... 你有没有想过,让你的车载安卓系统也能玩转CarPlay呢?想象在驾驶途中,一边享受着安卓系统的流畅操...
安卓13采用华为系统,引领智能... 你知道吗?最近安卓界可是炸开了锅,因为安卓13系统竟然要和华为系统来一场“亲密接触”呢!这可不是闹着...
安卓系统分类排名,解析热门应用... 你有没有想过,手机里的安卓系统竟然也有自己的“江湖地位”?没错,就是那个我们每天离不开的操作系统,它...
安卓系统把视频设为铃声,如何将... 你有没有想过,手机里的视频竟然能变成铃声?是的,你没听错,安卓系统竟然有这样的神奇功能!今天,就让我...
边锋杭麻圈安卓系统,边锋科技引... 你有没有听说过边锋杭麻圈安卓系统?这可是最近在游戏圈里火得一塌糊涂的存在哦!想象你正坐在家里,手握着...
ios系统能转移到安卓系统,轻... 你有没有想过,有一天你的手机从iOS系统跳转到安卓系统,会是怎样的体验呢?这可不是天方夜谭,随着科技...
安卓系统网络连接查看,安卓系统... 你有没有遇到过这种情况:手机里装了各种APP,可就是不知道哪个在偷偷消耗着你的流量?别急,今天就来教...
什么安卓系统优化的好,打造流畅... 你有没有发现,手机用久了,就像人一样,会变得有些“臃肿”呢?尤其是安卓系统,有时候感觉就像一个老态龙...
手机安卓系统ios系统怎么安装... 你有没有发现,现在手机里的软件真是五花八门,让人眼花缭乱?无论是安卓系统还是iOS系统,都能轻松安装...
按音量键报警安卓系统,安卓系统... 你有没有遇到过这种情况:手机突然发出刺耳的警报声,吓得你心跳加速,还以为发生了什么大事?别担心,今天...
安卓系统改win版系统怎么安装... 你有没有想过,把你的安卓手机换成Windows系统的电脑呢?想象那流畅的触控体验和强大的办公功能,是...
安卓系统如何备份到苹果,轻松实... 你是不是也有过这样的烦恼:手机里的照片、联系人、应用数据等等,突然间就消失得无影无踪?别担心,今天就...
修改安卓系统参数设置,安卓系统... 你有没有发现,你的安卓手机有时候就像一个不听话的小孩子,总是按照自己的节奏来,让你有点头疼?别急,今...
安卓手机gps定位系统,畅享智... 你有没有发现,现在不管走到哪里,手机都能帮你找到路?这都得归功于安卓手机的GPS定位系统。想象你站在...
华为不能安卓系统升级,探索创新... 你知道吗?最近有个大新闻在科技圈里炸开了锅,那就是华为的新款手机竟然不能升级安卓系统了!这可真是让人...
汽车加装安卓系统卡住,探究原因... 你有没有遇到过这样的尴尬情况:汽车加装了安卓系统,结果屏幕突然卡住了,就像被施了魔法一样,怎么也动弹...
电量壁纸安卓系统下载,打造个性... 手机电量告急,是不是又得赶紧找充电宝了?别急,今天就来给你安利一款超实用的电量壁纸,让你的安卓手机瞬...