数据结构常用算法总结(一)AVL,Dijkstra,Floyd
2022/1/31 12:34:18
本文主要是介绍数据结构常用算法总结(一)AVL,Dijkstra,Floyd,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
一,建立使用AVL树
#include<iostream> #include<queue> using namespace std; struct Node {//二叉树结点 Node* left; Node* right; int key; Node(int a) { key = a; left = nullptr; right = nullptr; } }; class AvlTree { public: Node* roots; AvlTree() { roots = nullptr; } Node* L(Node* root) { Node* temp = root->right; root->right = temp->left; temp->left = root; return temp; } Node* R(Node* root) { Node* temp = root->left; root->left = temp->right; temp->right = root; return temp; } int get_Height(Node* root) { if (root == nullptr) return 0; return max(get_Height(root->left), get_Height(root->right)) + 1; } Node* insert(Node* root, int key) { if (root == nullptr) { root = new Node(key); } else if (root->key > key) {//在左子树中插入 root->left = insert(root->left, key); if (get_Height(root->left) - get_Height(root->right) == 2) {//因为是递归算法,所以这里检测到的就是最小不平衡子树 if (get_Height(root->left->left) - get_Height(root->left->right) == 1) { root = R(root); } else if (get_Height(root->left->left) - get_Height(root->left->right) == -1) { root->left = L(root->left); root = R(root); } } } else { root->right = insert(root->right, key); if (get_Height(root->left) - get_Height(root->right) == -2) { if (get_Height(root->right->left) - get_Height(root->right->right) == -1) { root = L(root); } else if (get_Height(root->right->left) - get_Height(root->right->right) == 1) { root->right = R(root->right); root = L(root); } } } return root; } void StoreyLook()//层序遍历 { //初始化队列 queue<Node> q; q.push(*roots); while (!q.empty()) { cout<<(q.front()).key<<' '; if ((q.front()).left != nullptr) { q.push(*(q.front().left)); } if ((q.front()).right != nullptr) { q.push(*(q.front().right)); } q.pop(); } } void DFS(Node* root, int target,Node* res=nullptr, int depth=1)//深度优先遍历查找target——先序(根,左,右),顺便计算结点深度 { if (root != nullptr) { if (root->key == target) res = root; else { DFS(root->left,target,res,depth + 1); DFS(root->right,target,res,depth + 1); } } if (depth == 1 && res == nullptr) { cout << "该值不存在" << endl; } } }; int main() { AvlTree obj; int k; cin >> k; for (int i = 0; i < k; i++) { int value; cin >> value; obj.roots=obj.insert(obj.roots, value); }//插入结点建立AVL树 obj.StoreyLook();//层序遍历 cout << endl<<obj.get_Height(obj.roots); Node* res=nullptr; obj.DFS(obj.roots, 3, res);//在obj树中查找数字3,如果存在,记录3结点的地址到res }
收获:深刻掌握递归算法。
二,图有关算法
1,迪杰斯特拉算法(重点)
#include<iostream> #include<vector> #include<Windows.h> using namespace std; const int Max = 9999; struct edge { int cost; int eid; }; void input(int& k,int &m,vector<edge>*map) { cout << "请输入图中有多少结点" << endl; cin >> k;//图中有多少结点 cout << "请输入图中有多少条边" << endl; cin >> m; cout << "请输入图中所有的边 起点id-终点id-代价,例如 0 1 4" << endl; for (int i = 0; i < m; i++) { int start, end,cost; cin >> start >> end>>cost; edge a1; edge a2; a1.eid = start; a1.cost = cost; a2.eid = end; a2.cost = cost; map[start].push_back(a2); map[end].push_back(a1); } } void searchLoad(vector<edge>* map, int start,int k) { cout << "开始计算从" << start << "出发,到达所有结点的最短路径" << endl; int dist[100];//每个结点距离出发点的最短距离 int path[100];//记录每个结点的上一条路径 bool flag[100];//记录每个结点是否被处理过 //初始化 for (int i = 0; i < k; i++) { dist[i] = Max; path[i] = -1; flag[i] = false; } dist[start] = 0; //贪心求解子问题最优解 for (int i = 0; i < k; i++)//找第i条路径 { int min = Max; int min_id = -1; for (int j = 0; j < k; j++){ if ((!flag[j])&& (dist[j] < min)) { min = dist[j]; min_id = j; } }//贪心找到了第i个子问题 flag[min_id] = true; if (min_id == -1)return;//说明该图不连通 for (int t = 0; t < map[min_id].size(); t++){ int eid = map[min_id][t].eid; int cost = map[min_id][t].cost; if ((!flag[eid])&& (dist[min_id] + cost < dist[eid])) { dist[eid] = dist[min_id] + cost; path[eid] = min_id; } } } cout << "最短路径如下" << endl; //输出路径 for (int i = 0; i < k; i++) { cout << path[i] << ' '; } } int main() { vector<edge> map[100]; int k;//图中结点的个数 int m;//图中边的个数 input(k,m,map); int start;//开始城市的id cout << "请输入开始城市的id" << endl; cin >> start; searchLoad(map,start, k); }
2,BFS算法(单源最短路径算法)每个路径长度默认为1才能算
比较简单,注意先访问,再入队。
3,弗洛伊德算法(多源最短路径)
弗洛伊德算法是一个求解图最短路径的一个动态规划算法。
如上图:将图用邻接表A存储,用path[i][j]存储从i到j的中转站。现在用动态规划的思想来解决这个问题。
动态规划状态转移递归方程
A[i][j]=min{ A[i][j],A[i][k]+A[k][j]},0<=k<=j。
因此,动态规划的核心算法如下
void floyd(int** A, int** path, int n) { for (int k = 0; k < n; k++) {//考虑以vk为中转点 for (int i = 0; i < n; i++) {//遍历整个矩阵,i为行号,j为列号 for (int j = 0; j < n; j++){ if (A[i][j] > A[i][k] + A[k][j]) {//以vk为中转点的路径长度更短 A[i][j] = A[i][k] + A[k][j];//更新最短路径长度 path[i][j] = k;//记录中转点 } } } } }
该算法因为是求多源最短路径,算法复杂度为n^3,一般算法题目中涉及图的化不好考察。
——如何理解上面的状态转移方程
观察整个代码运行
1,判断从某个结点直接到某个结点的最短路径
2,判断从某个结点使用某个中转点到某个结点的最短路径
3,判断从某个结点使用再一个中转点到某个结点的路径
4,…
表面上看我们仿佛看的是
vi->vj
vi->v0->vj
vi->v1->vj
vi->v2->vj等等的最短路径
实际上就比如vi->v1->vj这条路径中,v1->vj可不是说v1直接到vj,v1->vj也是一条递归的路径。理解了这层递归,相信整个动态规划递归方程不难理解。
这篇关于数据结构常用算法总结(一)AVL,Dijkstra,Floyd的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-28一步到位:购买适合 SEO 的域名全攻略
- 2024-12-27OpenFeign服务间调用学习入门
- 2024-12-27OpenFeign服务间调用学习入门
- 2024-12-27OpenFeign学习入门:轻松掌握微服务通信
- 2024-12-27OpenFeign学习入门:轻松掌握微服务间的HTTP请求
- 2024-12-27JDK17新特性学习入门:简洁教程带你轻松上手
- 2024-12-27JMeter传递token学习入门教程
- 2024-12-27JMeter压测学习入门指南
- 2024-12-27JWT单点登录学习入门指南
- 2024-12-27JWT单点登录原理学习入门