啊哈!算法 案例用c++实现
第二章
我觉得此章节的数据结构可以实现一下
栈
数组实现栈
#include<iostream>using namespace std;struct stack
{int top;//下一个应该放的元素位置int mCapacity;int *p;stack(int capacity){mCapacity = capacity;p = new int[mCapacity];top = 0;}int pop(){if (top==0){cout << "栈是空的" << endl;}else{top--;//默认下一个位置就是待插入元素就可以了,并没有实际删除return p[top];}return -1;}int push(int x){int ret = -1;if (top>=mCapacity){cout << "已经满了" << endl;}else{p[top] = x;top++;ret = x;}return ret;}int gettop(){if (top==0){return -1;}else{return p[top-1];}}int getsize(){return top;}
};
int main()
{stack s(5);/*for (int i=0;i<5;i++){s.push(i);cout << "size()="<< s.getsize() << endl;}for (int i = 0;i <10;i++){cout << "pop()=" << s.pop() << endl;}*///cout << "size()=" << s.getsize() << endl;for (int i =3;i < 5;i++){s.push(i);cout << "gettop()=" << s.gettop() << endl;//cout << "size()=" << s.getsize() << endl;}}
链表实现栈
#include<iostream>using namespace std;//只能实现头插法,才能用链表
struct Node
{int data;Node *next;Node(){data = 0;next = nullptr;}Node(int x){data =x;next = nullptr;}
};struct linStack
{Node * dummpy;linStack(){dummpy = new Node();}int pop(){if (dummpy->next==NULL)//只有一个空节点,{cout << "栈现在是空的" << endl;return -1;}else//注意一定要采用头插法{int ret = dummpy->next->data;dummpy->next = dummpy->next->next;return ret;}}int push(int x){Node * newnode = new Node(x);newnode->next = dummpy->next;dummpy->next = newnode;return -1;}int getTop(){if (dummpy->next!=nullptr){return dummpy->next->data;}else{return -1;}}int getsize(){Node * p = dummpy->next;int count = 0;while (p != nullptr){count++;p = p->next;}return count;}};int main()
{linStack s;for (int i=0;i<5;i++){s.push(i);//cout << "getsize=" << s.getsize() << endl;}for (int i = 0;i < 10;i++){cout << "pop()=" << s.pop() << endl;}for (int i = 3;i < 10;i++){s.push(i);cout << "s.top()=" << s.getTop() << endl;}}
队列:
数组实现循环队列
#include<iostream>
#include<algorithm>
using namespace std;struct quque
{int mCapacity;int *p;int head ;int tail;quque(int capacity){mCapacity = capacity;p = new int[mCapacity];tail = 0;//top是代表下一个位置需要插入的数head = 0;}int front(){int size = abs(tail - head);if (size == 0) return -1;else return p[head];//每次就是头部这里出去}int push(int x){if ((tail+1)%mCapacity ==head) //这代表满了{return -1;}else{p[tail] = x;tail = (tail + 1) % mCapacity;return 1;}}int pop(){if (head==tail)//空{return -1;}else{int ret = front();head = (head + 1) % mCapacity;return ret;}}int getsize(){return (tail-head+mCapacity)%mCapacity;}
};int main()
{quque qu(5);for (int i=0;i<5;i++){qu.push(i);}cout << qu.getsize() << endl;;int n = qu.getsize();for (int i = 0;i < 100;i++){cout << "qu.getsize()=" << qu.getsize() << endl;int front = qu.pop();cout << front << endl;}}
链表实现队列(注意head指针实现 删除 tail指针实现插入,借助dummpy节点,需要需要注意的是当只有一个节点进行删除的时候,注意需要tail=front,防止丢失tail指针)
#include<iostream>
using namespace std;struct Node
{int data;struct Node *next;Node(){data = 0;next = nullptr;}Node(int x){data = x;next = nullptr;}
};struct queue
{struct Node * head, *tail;queue(){head = new (Node);tail = head;cout << "...构造函数" << endl;}
};int push(queue &que,int x)
{Node * newNode = new Node(x);que.tail->next = newNode;que.tail = que.tail->next;return -1;}int pop(queue &que)
{int ret = -1;/*if (que.head!=que.tail)*///证明链中至少存在一个元素//cout << que.head->data << " " << que.tail->data << endl;if (que.head != que.tail){ret = que.head->next->data;//100if (que.head->next->next==nullptr){que.head->next = que.head->next->next;que.tail = que.head;}else{que.head->next = que.head->next->next;}}else{cout << "我们发现相等啊" << endl;}return ret;
}int getsize(queue que)
{Node * p = que.head->next;int size = 0;while (p!=NULL){p = p->next;size++;}return size;
}int main()
{queue qu;for (int i=0;i<5;i++){push(qu, i);//cout << "getsize()=" << getsize(qu) << endl;}for (int i = 0;i < 10;i++){cout << "pop=" << pop(qu) << endl;}
题目2.1:
思路:
题目其实已经给出思路了
代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;class Solution {public:vector<int> deCode(vector<int>& nums) {vector<int> ret_v;queue<int> qu;for (int i=0;i<nums.size();i++){qu.push(nums[i]);}while (!qu.empty()){//将删除的元素放到 ret中ret_v.push_back(qu.front());qu.pop();if (!qu.empty()){// 然后将元素放到队列的尾端int front = qu.front();qu.pop();qu.push(front);}}return ret_v;}
};int main()
{vector<int> nums{ 6,3 ,1,7,5,8,9,2,4 };Solution s;vector<int> ret_v=s.deCode(nums);for (auto one: ret_v){cout << one << " ";}
}
题目2.2
思路:
桌子上面的牌用vector保存
哼哈二将手中的牌用 队列保存就可以了。
需要注意一点 拖拉机里面的收牌加到尾部方式是,依次将弹出的牌加到尾部就可以了。
代码:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;class Solution {private:void doLoad(vector<int> &restore, queue<int> &qu){int front = qu.front();qu.pop();auto it = find(restore.begin(), restore.end(), front);if (it != restore.end()){vector<int> append_v;append_v.push_back(front);//拖拉机里面的第一个数就是我们的front//需要弹出 将其补到restore的尾端int j = int(restore.size()) - 1;//避免无符号转换while (j >= 0 && restore[j] != front)//这里肯定能找到 restore[j]{append_v.push_back(restore[j]);restore.pop_back();//这个千万不要忘记j--;//不要忘记了}append_v.push_back(restore[j]);//这个是最后一个restore.pop_back();for (int val : append_v){qu.push(val);}}else{//直接加入到restore中restore.push_back(front);}}
public:/*返回true代表nums1会赢 否则false*/bool doTractor(vector<int>& nums1,vector<int>& nums2) {vector<int> restore;queue<int> qu1;for (auto value : nums1) qu1.push(value);queue<int> qu2;for (auto value : nums2) qu2.push(value);while (!qu1.empty()&&!qu2.empty()){cout << "qu1.size()=" << qu1.size() << " qu2.size()=" << qu2.size() << " restore.size()=" << restore.size() << endl;doLoad(restore, qu1);//先进行qu1的操作if (qu1.empty()) break;doLoad(restore, qu2);再进行qu2的操作if (qu2.empty()) break;}cout << "结果返回值" << endl;cout << "qu1.size()=" << qu1.size() << " qu2.size()=" << qu2.size() << " restore.size()=" << restore.size() << endl;if (!qu1.empty()){cout << "小哼赢了" << endl;while (!qu1.empty()){cout << " " << qu1.front();qu1.pop();}cout << endl;cout << "桌子上面的牌" << endl;for (int val:restore){cout << " " << val;}cout << endl;return true;}else{cout << "小哈赢了" << endl;while (!qu2.empty()){cout << " " << qu2.front();qu2.pop();}cout << endl;cout << "桌子上面的牌" << endl;for (int val : restore){cout << " " << val;}cout << endl;return false;}}
};int main()
{vector<int> nums1{ 2,4,1,2,5,6 };vector<int> nums2{3,1,3,5,6,4};Solution s;bool ret_b = s.doTractor(nums1, nums2);//cout << ret_b << endl;
}
我的代码运行结果
第三章
题目3.1
leetcode题目链接
题目
46. 全排列
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
思路:
dfs的思想,这里的index并不代表元素的下标,只是代表元素的个素,我习惯在dfs里面用index表示递归的深度。
代码:
class Solution {private:vector<vector<int>> ret_vv;void dfs(vector<int>& nums,vector<bool>& used,vector<int>& temp,int index){if(index>=nums.size()){ret_vv.push_back(temp);return;}for(int i=0;i<nums.size();i++){if(used[i]==true) continue;temp.push_back(nums[i]);used[i]=true;dfs(nums,used,temp,index+1);temp.pop_back();used[i]=false;}}
public:vector<vector<int>> permute(vector<int>& nums) {vector<bool> used(nums.size(),false);vector<int > temp;int index=0;dfs(nums,used,temp,index);return ret_vv;}
};
提升:
leetcode题目链接
47. 全排列 II
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
示例 2:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
思路:
我们可以发现此题与题目3.1只有一点不同,返回所有不重复的全排列。
这里面涉及到一个同一树层剪枝和树枝剪枝
方法一:同一树层(这个更快)
if(i>0&&nums[i]==nums[i-1]&&isUse_v[i-1]==false) continue;
方法二:树枝剪枝
if(i>0&&nums[i]==nums[i-1]&&isUse_v[i-1]==true) continue;
代码:
class Solution {private:void dfs(int index,vector<int>& nums,vector<bool> &isUse_v,vector<vector<int>> &result_vv,vector<int>&temp_v){if(index>=nums.size()){result_vv.push_back(temp_v);return;}for(int i=0;i<nums.size();i++){if(isUse_v[i]==true) continue;if(i>0&&nums[i]==nums[i-1]&&isUse_v[i-1]==false) continue;temp_v.push_back(nums[i]);isUse_v[i]=true;dfs(index+1,nums,isUse_v,result_vv,temp_v);isUse_v[i]=false;temp_v.pop_back();}}public:vector<vector<int>> permuteUnique(vector<int>& nums) {vector<vector<int>>result_vv;vector<int>temp_v;vector<bool> isUse_v(nums.size(),false);sort(nums.begin(), nums.end());dfs(0,nums,isUse_v,result_vv,temp_v);return result_vv;}
};
第四章
题目4.1
全排列问题
思路:
dfs 上面题目3.1已经写过了。
代码:
同层剪枝(假设不能有重复的排列情况)
class Solution {private:void dfs(int index,vector<int>& nums,vector<bool> &isUse_v,vector<vector<int>> &result_vv,vector<int>&temp_v){if(index>=nums.size()){result_vv.push_back(temp_v);return;}for(int i=0;i<nums.size();i++){if(isUse_v[i]==true) continue;if(i>0&&nums[i]==nums[i-1]&&isUse_v[i-1]==false) continue;temp_v.push_back(nums[i]);isUse_v[i]=true;dfs(index+1,nums,isUse_v,result_vv,temp_v);isUse_v[i]=false;temp_v.pop_back();}}public:vector<vector<int>> permuteUnique(vector<int>& nums) {vector<vector<int>>result_vv;vector<int>temp_v;vector<bool> isUse_v(nums.size(),false);sort(nums.begin(), nums.end());dfs(0,nums,isUse_v,result_vv,temp_v);return result_vv;}
};
题目4.2:
思路:
dfs,注意每次的递归终止条件是index>=nums.size()
A+B=C
最后的temp中 需要分离出 A,B,C
代码:
#include<iostream>
#include<vector>
using namespace std;class Solution {private:bool Compare(int temp){//A+B=C;int a[3];int i = 0;while (temp != 0){a[i] = temp % 1000;temp = temp / 1000;i++;}//A+B==C?if (a[2] + a[1] == a[0]){cout << a[2] << "+" << a[1] << "=" << a[0] << endl;return true;}else return false;}void dfs(vector<int>& nums, vector<bool>& used, int temp, int index ){if (index>= nums.size()){if (Compare(temp)) sum++;return;}for (int i=0;i<nums.size();i++){if (used[i] == true) continue;used[i] = true;dfs(nums, used, temp * 10 + nums[i], index+1);//千万要注意我们没有传 temp引用,ndex引用used[i] = false;}}int sum = 0;
public:int permuteSumDiff(vector<int>& nums){int temp = 0;//这个是存每次递归的和int index = 0;vector<bool> used(nums.size(),false);//标志位dfs(nums, used, temp,index );return sum;}
};
int main()
{vector<int> numbers{ 1,2,3,4,5,6,7,8,9 };Solution s;int sum=s.permuteSumDiff(numbers);cout << "sum=" << sum << endl;}
结果展示:
题目4.3
迷宫最短路径
思路:
其实这就是迷宫问题,由于我对于迷宫问题,喜欢将第一个点先拎出来,然后进行dfs
代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;class Solution {private:int global_step = INT_MAX;vector<vector<int>> dxy{ {0,1},{1,0},{0,-1}, {-1,0}};//走的方向依次是 右下左上bool isArea(vector<vector<int>> &maze,int temp_x,int temp_y){if (temp_x < 0 || temp_x >= maze.size() || temp_y < 0 || temp_y >= maze[0].size()) return false;return true;}void dfs(vector<vector<int>> &maze, vector<vector<bool>> &used,int current_i, int current_j, int target_i, int target_j, int &step){if (current_i == target_i&& current_j == target_j){global_step = min(global_step,step);return;}for (int i=0;i < dxy.size();i++){int temp_i = current_i + dxy[i][0];int temp_j = current_j + dxy[i][1];if (isArea(maze, temp_i, temp_j) && maze[temp_i][temp_j] == 0 &&used[temp_i][temp_j] == false){used[temp_i][temp_j] = true;step++;dfs(maze, used, temp_i, temp_j, target_i, target_j, step);step--;used[temp_i][temp_j] = false;}}}public:int getShortpath(vector<vector<int>> &maze, int start_i, int start_j, int target_i, int target_j) //maze中0代表可走,1代表是障碍物{vector<vector<bool>> used(maze.size(), vector<bool>(maze[0].size(), false));if (isArea(maze, start_i, start_j) && used[start_i][start_j] == false)//这里防止刚开始位置越界{used[start_i][start_j] = true;int step = 0;dfs(maze, used, start_i, start_j, target_i, target_j, step);}return global_step;}
};int main()
{vector<vector<int>> maze{{0,0,1,0},{0,0,0,0},{0,0,1,0},{0,1,0,0},{0,0,0,1} };int start_i = 0;int start_j = 0;int target_i = 3;int target_j = 2;Solution s;int path=s.getShortpath(maze, start_i, start_j, target_i, target_j);cout << "path=" << path << endl;
}
结果展示:
题目4.4
迷宫广度优先搜索
思路:
首先我们需要明确一点,在迷宫问题中采用bfs(广度优先遍历)会得到满足一个符合条件的。但可能不是最短路径。主要是进行迭代
代码:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;class Solution {private:vector<vector<int>> dxy{ {0,1},{1,0},{0,-1}, {-1,0} };//走的方向依次是 右下左上bool isArea(vector<vector<int>> &maze, int temp_x, int temp_y){if (temp_x < 0 || temp_x >= maze.size() || temp_y < 0 || temp_y >= maze[0].size()) return false;return true;}public:int getShortpath(vector<vector<int>> &maze, int start_i, int start_j, int target_i, int target_j) //maze中0代表可走,1代表是障碍物{vector<vector<bool>> used(maze.size(), vector<bool>(maze[0].size(), false));if (isArea(maze, start_i, start_j) && used[start_i][start_j] == false)//这里防止刚开始位置越界{used[start_i][start_j] = true;int step = 0;queue<pair<int, int>> qu;qu.emplace(start_i, start_j);while (!qu.empty()){int n = qu.size();for (int i=0;i<n;i++){auto node = qu.front();qu.pop();//一定记得popint current_i = node.first;int current_j = node.second;//cout << "current_i=" << current_i << " current_j=" << current_j << " step="<< step << endl;if (current_i == target_i && current_j == target_j){return step;}for (int i = 0;i < dxy.size();i++){int temp_i = current_i + dxy[i][0];int temp_j = current_j + dxy[i][1];if (isArea(maze, temp_i, temp_j) &&maze[temp_i][temp_j]==0&& used[temp_i][temp_j] == false){cout << "temp_i=" << temp_i << " temp_j=" << temp_j << " step=" << step << endl;used[temp_i][temp_j] = true;qu.emplace(temp_i, temp_j);}}}cout << "*******************" << endl;for (int i=0;i<used.size();i++){for (int j = 0;j<used[0].size();j++){cout << used[i][j] << " ";}cout << endl;}cout << endl;cout << "*******************" << endl;step++;}}return INT_MAX;}
};int main()
{vector<vector<int>> maze{{0,0,1,0},{0,0,0,0},{0,0,1,0},{0,1,0,0},{0,0,0,1} };int start_i = 0;int start_j = 0;int target_i = 3;int target_j = 2;Solution s;int path = s.getShortpath(maze, start_i, start_j, target_i, target_j);cout << "path=" << path << endl;}
题目4.5
思路递归过程中用floodfill方法,其实就是used[i][j]=true后,不在进行恢复,减少重复操作,然后在每个合格点再进行判断消除的怪兽数目,保存可以消灭怪兽的最多数
代码:略
题目4.6
floodfilld应用
求飞机降落点中的岛屿快的总面积
思路:
我是比较喜欢
代码:
#include<iostream>
#include<vector>using namespace std;class Solution {private:vector<vector<int>> dxy{ {0,1},{1,0},{0,-1}, {-1,0} };//走的方向依次是 右下左上bool isArea(vector<vector<int>>& grid, int temp_i, int temp_j){if (temp_i < 0 || temp_i >= grid.size() || temp_j < 0 || temp_j >= grid[0].size()) return false;return true;}int s = 0;//这个是可以这样进行赋值的void dfs(vector<vector<int>>&grid, vector<vector<bool>>& used, int current_i, int current_j){for (int i = 0;i < dxy.size();i++){int temp_i = current_i + dxy[i][0];int temp_j = current_j + dxy[i][1];if (isArea(grid, temp_i, temp_j) && grid[temp_i][temp_j] > 0 && used[temp_i][temp_j] == false){used[temp_i][temp_j] = true;s++;grid[temp_i][temp_j] = s;dfs(grid, used, temp_i, temp_j);//used[temp_i][temp_j] = false; floodfill 就是不要这句话}}}
public:int islandArea(vector<vector<int>>& grid,int start_i,int start_j){vector<vector<bool>> used(grid.size(), vector<bool>(grid[0].size(), false));if (isArea(grid,start_i,start_j)&&used[start_i][start_j]==false){if (grid[start_i][start_j] > 0){used[start_i][start_j] = true;s++;grid[start_i][start_j] = s;dfs(grid, used, start_i, start_j);}}cout << "*******************" << endl;for (int i = 0;i < grid.size();i++){for (int j = 0;j < grid[0].size();j++){//cout << grid[i][j] << " ";printf("%5d", grid[i][j]);}cout << endl;}cout << endl;cout << "*******************" << endl;return s;}
};int main()
{vector<vector<int>> maze{{1,2,1,0,0,0,0,0,2,3},{3,0,2,0,1,2,1,0,1,2},{4,0,1,0,1,2,3,2,0,1},{3,2,0,0,0,1,2,4,0,0},{0,0,0,0,0,0,1,5,3,0},{0,1,2,1,0,1,5,4,3,0},{0,1,2,3,1,3,6,2,1,0}, {0,0,3,4,8,9,7,5,0,0}, {0,0,0,3,7,8,6,0,1,2}, {0,0,0,0,0,0,0,0,1,0}, };int start_i = 5;int start_j = 7;Solution s;int sum = s.islandArea(maze, start_i, start_j);cout << "sum=" << sum << endl;
}
运行结果
我们可以看到floodfill的运行效果截图,
题目4.7
leetcode200. 岛屿数量
题目:
思路:
floodfill,相比较题目4.6而言,需要在main函数中套上循环遍历grid
代码:
class Solution {private:vector<vector<int>> dxy{ {0,1},{1,0},{0,-1}, {-1,0} };//走的方向依次是 右下左上bool isArea(vector<vector<char>>& grid, int temp_i, int temp_j){if (temp_i < 0 || temp_i >= grid.size() || temp_j < 0 || temp_j >= grid[0].size()) return false;return true;}int count = 0;//这个是可以这样进行赋值的void dfs(vector<vector<char>>&grid, vector<vector<bool>>& used, int current_i, int current_j){for (int i = 0;i < dxy.size();i++){int temp_i = current_i + dxy[i][0];int temp_j = current_j + dxy[i][1];if (isArea(grid, temp_i, temp_j) && grid[temp_i][temp_j] !='0' && used[temp_i][temp_j] == false){used[temp_i][temp_j] = true;dfs(grid, used, temp_i, temp_j);//used[temp_i][temp_j] = false; floodfill 就是不要这句话}}}
public:int numIslands(vector<vector<char>>& grid){vector<vector<bool>> used(grid.size(), vector<bool>(grid[0].size(), false));for (int start_i=0;start_i<grid.size();start_i++){for (int start_j = 0;start_j < grid[0].size();start_j++){if (isArea(grid, start_i, start_j) && used[start_i][start_j] == false){if (grid[start_i][start_j] != '0'){used[start_i][start_j] = true;count++;dfs(grid, used, start_i, start_j);}}}}return count;}
};
题目4.8
思路:
这题首先从start_i=0,start_j=0出开始找路,所以第一个水管是
中形状,然后采用dfs看有没够水管能够与第一个水管接上的,接上了就继续dfs,依次寻找,直到到达出口,当某一个水管接不上时,如果无论怎么旋转方向都不满足,回溯,转换当前不满足水管的方向,如果还是不满足,那么就可以后退一个,再次判定,代码中也是需要used判断水管位置的访问状态的
代码:
略
第五章:
图论
第六章
最短路径
题目:求某个点到某个结束点的最短路径
其实这个问题涉及到的问题很广,实用性贼强,下面介绍三个算法
游戏中寻路算法
6.1.1方法一:广度优先搜索算法
//bfs寻路算法 确定也明显 没有像 迪杰斯特拉算法中的最短路径一样。也就是没有权值,不能找到最短的
代码
//bfs寻路算法 确定也明显 没有像 迪杰斯特拉算法中的最短路径一样。也就是没有权值,不能找到最短的//used[temp_i][temp_j] = true; bfs没有对应的 false这是和bfs不一样的
#include<iostream>
#include<vector>
#include<queue>
using namespace std;#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;class Solution {private:vector<vector<int>> dxy{ {0,1},{1,0},{0,-1}, {-1,0} };//走的方向依次是 右下左上bool isArea(vector<vector<int>> &maze, int temp_x, int temp_y){if (temp_x < 0 || temp_x >= maze.size() || temp_y < 0 || temp_y >= maze[0].size()) return false;return true;}public:int getShortpath(vector<vector<int>> &maze, int start_i, int start_j, int target_i, int target_j) //maze中0代表可走,1代表是障碍物{vector<vector<bool>> used(maze.size(), vector<bool>(maze[0].size(), false));if (isArea(maze, start_i, start_j) && used[start_i][start_j] == false)//这里防止刚开始位置越界{used[start_i][start_j] = true;int step = 0;queue<pair<int, int>> qu;qu.emplace(start_i, start_j);while (!qu.empty()){int n = qu.size();for (int i = 0;i < n;i++){auto node = qu.front();qu.pop();//一定记得popint current_i = node.first;int current_j = node.second;//cout << "current_i=" << current_i << " current_j=" << current_j << " step="<< step << endl;if (current_i == target_i && current_j == target_j){return step;}for (int i = 0;i < dxy.size();i++){int temp_i = current_i + dxy[i][0];int temp_j = current_j + dxy[i][1];if (isArea(maze, temp_i, temp_j) && maze[temp_i][temp_j] == 0 && used[temp_i][temp_j] == false){cout << "temp_i=" << temp_i << " temp_j=" << temp_j << " step=" << step << endl;used[temp_i][temp_j] = true;qu.emplace(temp_i, temp_j);}}}cout << "*******************" << endl;for (int i = 0;i < used.size();i++){for (int j = 0;j < used[0].size();j++){cout << used[i][j] << " ";}cout << endl;}cout << endl;cout << "*******************" << endl;step++;}}return INT_MAX;}
};int main()
{vector<vector<int>> maze{{0,0,1,0},{0,0,0,0},{0,0,1,0},{0,1,0,0},{0,0,0,1} };int start_i = 0;int start_j = 0;int target_i = 3;int target_j = 2;Solution s;int path = s.getShortpath(maze, start_i, start_j, target_i, target_j);cout << "path=" << path << endl;}
题目:
6.1.2迪杰斯特拉算法 可以找到所有的节点最短路径,
求以某一起始点到另外所有结点的最短路径dist
思路:
首先对应的二维矩阵是
其次我们需要明白 迪杰斯特拉(Dijkstra)是针对连通图来说的。
代码最重要的两个变量
vector<int> visit(n,0);//0代表未访问节点,1代表访问节点vector<int> dist(n, 0);//后面会根据start进行初始化,这里初始化值是任何值都没关系
主要思路是,首先将start节点先拎出来,然后每次将最小的dist的没有访问的节点找到作为中转节点,然后以中转节点更新,dist的从起始节点到非访问节点的更小值。
代码:
//单源最短路径,迪杰斯特拉算法//总体思路,是将每次最短的还没有访问的节点作为中转节点,然后从寻找从中转节点到其他节点和之前的到start的节点路径作比较,
//更新每个未访问节点的最短路径,将中转节点设置成访问节点,进入下一次循环。
#include<iostream>
#include<vector>#define INF 999999//路径中不可达边 因此graph也应该这么写不可达边的长度using namespace std;class Solution {public:vector<int> Dijkstra(vector<vector<int>>& graph,int start){int n = graph.size();vector<int> visit(n,0);//0代表未访问节点,1代表访问节点vector<int> dist(n, 0);//后面会根据start进行初始化,这里初始化值是任何值都没关系//首先将第一个start节点的信息提取出来,为循环做出准备if (start>=n){cout << "起点位置不合法" << endl;return dist;}visit[start] = 1;// 设置起点位置已访问1for (int i=0;i<n;i++)//设置起点位置为初始位置,初始化dist{dist[i] = graph[start][i];}for (int i=1;i<n;i++)//第一个节点已经单独拎出来了个节点,所以我们需要循环n-1次{int minNumber = INF;int mind=1111;//我们从这里可以看出无论此处mind初始值是多少,如果不是连通图,可能会造成,死循环, 因此使用该算法的图应该是连通图 for (int j=0;j< dist.size();j++)//寻找中转节点 记住当前中转节点一定是未访问节点{if (visit[j]==0&& minNumber> dist[j]){minNumber = dist[j];mind = j;}}//cout << "mind=" << mind << endl;//visit[mind] = 1; //这个放在这里也是可以的//中转节点找到后,我们需要更新当前以中转节点和原点的 到其他非访问节点距离 for (int j=0;j<n;j++)//这里的j代表着节点的下标的意思{if (visit[j]==0&&dist[j]>dist[mind]+graph[mind][j])//这一步说明了graph中不能有INT_MAX不然可能会溢出{dist[j] = dist[mind] + graph[mind][j];}}visit[mind] = 1;//应该将中转节点设置成已访问}return dist;}
};int main()
{int n = 6;vector<vector<int>> graph(n, vector<int>(n, INF));for (int i=0;i<n;i++){graph[i][i] = 0;}graph[0][1] = 100;graph[1][0] = 100;graph[0][2] = 1200;graph[2][0] = 1200;graph[1][2] = 900;graph[2][1] = 900;graph[1][3] = 300;graph[3][1] = 300;graph[2][3] = 400;graph[3][2] = 400;graph[2][4] = 500;graph[4][2] = 500;graph[3][4] = 1300;graph[4][3] = 1300;graph[3][5] = 1400;graph[5][3] = 1400;graph[4][5] = 1500;graph[5][4] = 1500;Solution s;vector<int> dist;for (int j=0;j<n;j++){cout << "以索引值为start=" << j << "设置为起始点" << endl;dist = s.Dijkstra(graph, j);for (int i = 0;i < n;i++){cout << " " << dist[i];}cout << endl;}}
结果:
缺点:
迪杰斯特拉算法在寻路的网格中是无目的性的,(因为我们将每个节点的最短路径都找出来了,而不是找起点到给定终点的最短路径)
6.1.3方式三:A*算法视频参考链接
**A*算法,**可以确定最短路径(总代价最小) 总代价=当前代价+预估代价
当前代价:我们可以使用 当前位置到起点位置的步数
预估代价,说明不是一个确切的数字,我们可以使用 曼哈顿距离 表示当前位置和目标位置 这两个坐标的绝对值差的和 即|x1-x2|+|y1-y2|
思路:
总代价=当前代价+预估代价 我们每次将当前的节点的总代价,加入到优先队列priority_queue(注意,我们需要重写仿函数 从cmp,使得堆顶最小),
struce cmp
{operator()(node1,node2){return node1.step_cost+node1.cost_so_far>node2.step_cost+node2.cost_so_far}
]
代码:
待定
第七章
题目7.1
leetcode排序链接
堆排序
思路:
用数据实现堆排序
进行堆排序输出的过程其实可以看做是删除堆顶元素的重复的过程
堆排序输出
vector<int> temp_v = nums;//进行堆排序输出//大根堆建好后,开始进行堆顶元素cout << "堆排序后的数组逻辑为" << endl;for (int i=n-1;i>=0;i--)//这其实可以看做是一个删除的过程{swap(temp_v[0], temp_v[i]);sortHeap(temp_v, 0, i);//每次将最后一个位置确定后,循环n次1,这样数组就是有序的}
删除堆顶元素
void pop(vector<int>& nums){int n = nums.size();swap(nums[0], nums[n - 1]);cout << "删除的栈顶元素是" << nums.back() << endl;nums.pop_back();n = nums.size();//nums中已经删除一个元素了。因此需要重新取大小sortHeap(nums, 0, n);}
代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;class Solution {private:void sortHeap(vector<int>& nums,int index, int n)//我们需要建立大根堆{int max = index;int left_index = index * 2 + 1;int right_index = index * 2 + 2;if (left_index<n&&nums[left_index]>nums[max]){max = left_index;}if (right_index<n&&nums[right_index]>nums[max]){max = right_index;}if (max != index){swap(nums[max],nums[index]);sortHeap(nums, max, n);//这是一个下溯的过程}}
public:vector<int> Heap(vector<int>& nums) {int n = nums.size();for (int index=n/2-1;index >=0;index--) //index代表着我们的需要比对的初始化的数字的位置(上溯过程){sortHeap(nums, index, n);}vector<int> temp_v = nums;//进行堆排序输出//大根堆建好后,开始进行堆顶元素cout << "堆排序后的数组逻辑为" << endl;for (int i=n-1;i>=0;i--)//这其实可以看做是一个删除的过程{swap(temp_v[0], temp_v[i]);sortHeap(temp_v, 0, i);//每次将最后一个位置确定后,循环n次1,这样数组就是有序的}//cout << endl;return temp_v;}//插入void insert(vector<int>& nums,int x){nums.push_back(x);int n = nums.size();for (int index = n / 2 - 1;index >= 0;index--) //index代表着我们的需要比对的初始化的数字的位置(上溯过程){sortHeap(nums, index, n);}}//删除元素void pop(vector<int>& nums){int n = nums.size();swap(nums[0], nums[n - 1]);cout << "删除的栈顶元素是" << nums.back() << endl;nums.pop_back();n = nums.size();//nums中已经删除一个元素了。因此需要重新取大小sortHeap(nums, 0, n);}};int main()
{vector<int> nums{ 4,6,2,3,5,8,6,9,4,1,6 };Solution s;vector<int> ret=s.Heap(nums);for (int value:ret){cout << " " << value;}cout << endl;int n = nums.size();for (int i=0;i<n;i++){s.pop(nums);}s.insert(nums,5);s.insert(nums,4);s.insert(nums,10);n = nums.size();cout << "插入元素后重新删除" << endl;for (int i = 0;i < n;i++){s.pop(nums);}
}
运行结果
题目7.2
leetcode 684链接
确认图中有没有环
思路:
代码:
#include <iostream>
#include<algorithm>
#include<vector>
using namespace std;const int MAXN = 1e6 + 10;
int parent[MAXN], RANK[MAXN];void Init()
{for (int i=0;i< MAXN;i++){parent[i] = i;RANK[i] = 1;}
}
//寻找x的头部(非递归写法)
int Find(int x)
{int x_root = x;while (parent[x_root]!= x_root){x_root = parent[x_root];}return x_root;
}寻找x的头部(递归写法)
//int Find(int x)
//{//
// if (parent[x] == x)
// {// return x;
// }
// return Find(parent[x]);
//}int Union(int u, int v)
{u = Find(u);v = Find(v);if (u != v){if (RANK[u] > RANK[v] ){parent[v] = u;}else if(RANK[v] > RANK[u]){parent[u] = v;}else if (RANK[v]= RANK[u]){parent[v] = u;RANK[u]++;}return 1;}else{return 0;}}
int main()
{Init();vector<vector<int>> vv{ {0,1},{1,2},{1,3},{2,5},{2,4},{3,4}};for (int i=0;i< vv.size();i++){int u = vv[i][0];int v = vv[i][1];if (Union(u, v) == 0){cout << " 图中存在环" << endl;return 0;}}cout << " 图中不存在环" << endl;return 1;
}
啊哈!算法 案例用c++实现相关推荐
- spark 随机森林算法案例实战
随机森林算法 由多个决策树构成的森林,算法分类结果由这些决策树投票得到,决策树在生成的过程当中分别在行方向和列方向上添加随机过程,行方向上构建决策树时采用放回抽样(bootstraping)得到训练数 ...
- 转盘抽奖php,使用PHP实现转盘抽奖算法案例解析
这次给大家带来使用PHP实现转盘抽奖算法案例解析,使用PHP实现转盘抽奖算法的注意事项有哪些,下面就是实战案例,一起来看一下. 流程: 1.拼装奖项数组 2.计算概率 3.返回中奖情况 代码如下: 中 ...
- ML之LoR:利用LoR二分类之非线性决策算法案例应用之划分正负样本
ML之LoR:利用LoR二分类之非线性决策算法案例应用之划分正负样本 目录 输出结果 实现代码 输出结果 1.对数据集进行特征映射 2.正则化 → 正则化 → 过度正则化 实现代码 import nu ...
- python编程思维代码_Python编程快速上手——强口令检测算法案例分析
本文实例讲述了Python强口令检测算法.分享给大家供大家参考,具体如下: 强口令检测 题目如下: 写一个函数,它使用正则表达式,确保传入的口令字符串是强口令.强口令定义:长度不少于8个字符,同时包含 ...
- php分割金额_PHP实现红包金额拆分算法案例详解
这次给大家带来PHP实现红包金额拆分算法案例详解,PHP实现红包金额拆分算法的注意事项有哪些,下面就是实战案例,一起来看一下.<?php // 新年红包金额拆分试玩 class CBonus { ...
- 随机森林的java算法_spark 随机森林算法案例实战
随机森林算法 由多个决策树构成的森林,算法分类结果由这些决策树投票得到,决策树在生成的过程当中分别在行方向和列方向上添加随机过程,行方向上构建决策树时采用放回抽样(bootstraping)得到训练数 ...
- 《经典算法案例》01-10:如何打印质数表(六列版)
<经典算法案例> 01-10:如何打印质数表(六列版) 本文通过表格的形式罗列出了0~9999的自然数,以及在此区间内的所有质数,方便大家观察和研究. 提示:源码在文章末尾. 1.图示 ...
- 《经典算法案例》01-09:如何打印质数表(十列版)
<经典算法案例> 01-09:如何打印质数表(十列版) 本文通过表格的形式罗列出了0~9999的自然数,以及在此区间内的所有质数,方便大家观察和研究. 提示:源码在文章末尾. 1.图示法 ...
- 《经典算法案例》:听英文神曲不误算法
<经典算法案例> 听英文神曲不误算法 <Faded>是一首以电音的基本旋律作为主体辅乐的曲子,在经过原艾兰·沃克作者的调和下融入了空灵的女声,使得电音的旋律在女声的演绎 ...
- 高中计算机辗转相除法,高三数学教案:算法案例――辗转相除法
<高三数学教案:算法案例――辗转相除法>由会员分享,可在线阅读,更多相关<高三数学教案:算法案例――辗转相除法(7页珍藏版)>请在人人文库网上搜索. 1.算法案例 辗转相除法育 ...
最新文章
- 数据结构实验——中缀表达式转为后缀表达式
- 网络正常,但是网络图标上有黄色的三角图标
- mysql搜索_mysql 几种搜索引擎的比较
- 卷成这样,非逼我用RTX 3090?(深度学习GPU平台种草
- 解密诡异并发问题的幕后黑手:可见性问题
- Cobra命令行框架及使用
- java_opts gc回收器_jvm垃圾收集器与内存分配策略
- “赤膊贪凉”要不得 多喝蜜水防“秋燥”
- android中fragment如何保存edittext文本,如何在Android中使用DialogFragment进行文本输入?...
- 咖啡口味介绍及存储方式
- spring5.0学习笔记8
- 多指标评价方法-变异系数法的pathon实现
- js获取时分秒数据格式为YYYMMDDHHmm方法
- 【Apache Spark 】第 2 章下载 Apache Spark并开始使用
- 壹佰大米时代公司研究报告
- 嵌入式linux platform设备驱动
- networkx笔记
- Vue定时器设置 Vue简单定时任务
- ajax和flash,flask ajax请求后flash方法(消息闪现)无效问题的解决方法
- 100款现代科技感的英文字体打包分享
热门文章
- 最近看过的几本给我印象深刻的书
- 开办公司的流程(四川)
- 群晖双网口虚拟机openwrt主路由二级路由拨号上网配置
- 三十而立技术er的进击之路
- 贴片电阻丝印是什么意思
- Linux下挂载u盘和光盘,即移动存储设备
- 得到最好的两个worlds-让Android应用程序运行在PC上
- 文语通5.0破解版安装说明
- ubuntu安装anaconda报错:Cannot open xxx/anaconda3/conda.exe or archive xxx/anaconda3/conda.exe.pkg
- 南阳师范学院大一计算机老师,大学计算机A