算法篇-7-贪心算法-Huffman编码&Dijkstra单源最短路径&Kruskal最小生成树
来源:互联网 发布:vps绑定域名 编辑:程序博客网 时间:2024/05/29 13:02
本系列所有代码https://github.com/YIWANFENG/Algorithm-github
huffman编码
题目:
依据给定字符以及相应频率构造该字符的哈夫曼编码。
算法思路分析与相关公式:
Haffman即前缀码,用一棵二叉树即可标示,树叶表示给定的字符,每个字符的前缀码就是从树根到该字符所在的树叶的一条道路。二叉树的每一路分支的路径我们在向右时即为1 ,向左时即为0。构造一棵haffman树即可得出我们的编码。
要使空间节约,那么使用频率低的字符编码长点,使用频率高的编码短点,对应的为相应的叶子节点的深度值大或者小。我们每次选择总频率小的子树的合并为新子树(频率为子树总频率之和),然后如此重复来得到最终编码树。(叶子结点视为频率为该节点的频率)。
程序源代码:
class cmp {public: booloperator() (const int &a,const int &b) { if(a>b) return true; return false; }}; class CHuffmanChar {public: charc_; //保存字符 CHuffmanChar*parent_; //指向父节点 intchild_type_ ; //1==left子节点 0 == right}; class CHuffmanChar_Heap {public: intindex_; //原始编号 floatweight_; //权重 booloperator < (const CHuffmanChar_Heap &c2) const { return weight_ > c2.weight_; }}; void HuffmanEncoding(int n, const chardata[], float fre[]){ //Huffman编码 //n字符数量 //data[]原始字符 //fre[]字符出现的频率 CHuffmanCharhc[n + n-1]; //中间出现节点数n-1 inti, j; for(i=0;i<n; ++i) hc[i].c_ = data[i]; for(i=0;i<n+n-1; ++i) hc[i].parent_ = NULL; priority_queue<CHuffmanChar_Heap>q; CHuffmanChar_Heaph, hr; for(i=0;i<n; ++i) { h.index_= i; h.weight_ = fre[i]; q.push(h); } for(i=0;i<n-1; ++i) { h = q.top(); q.pop(); hr = q.top(); q.pop(); hc[h.index_].parent_ = &hc[n+i]; hc[h.index_].child_type_ = 1; hc[hr.index_].parent_ = &hc[n+i]; hc[hr.index_].child_type_ = 0; h.weight_ += hr.weight_; h.index_ = n+i; q.push(h); } charcode[n]; for(i=0;i<n; ++i) { //从子节点寻根而上 j = 0; CHuffmanChar *pc = &hc[i]; while(pc->parent_!=NULL) { code[j++]='1'-pc->child_type_; pc= pc->parent_; } cout<<hc[i].c_<<':'; for(j--; j>=0; j--) { cout<<code[j]; } cout<<'\n'; } }
Dijkstra单源最短路径
题目:
给定一带权有向图G=(V,E),求指定顶点X顶点的最短路径长度。
算法思路分析以及相关公式:
基本思想:设置顶点集合S并不断贪心扩充此集合。
首先确认两点,1:设从X到最短的顶点为x1(肯定是直达的),那么比这次短的顶点一定是直达的或者是从x1间接到达。 2:由1可知,设从X 到其他顶点第k短的是xk,(xk加入到S中),那么第k+1短的顶点一定是直达或者经过S中某点间接到达的。
做法是设置集合S,来收集已经知道X到该点的最短路径的点。E保存不知最短路径的点
1. 首先选择一个属于E的点u,使X到u路径最短。
2. 将u加入到S,在E中取出u,并计算在u加入S后对在E中的点与X的最短距离的影响。
即判断所有在E中的点c,是否存在从X到u,再从u到c的距离比原本X到c的距离小,若小则更新,否则不处理。
1.若S包含所有点,则结束否则重复上述过程。
程序源代码:
template <class T_>void Dijkstra_ShortestPath(int n,int v,T_dist[],int prev[], const T_ *c,const T_ INF){ //n:(in)顶点数量 //v:(in)源顶点索引(0-...) //dist[]"(out)从源定点 到每个定点的距离 //prev[]:(out) 在最短路径上每个定点的前面的一个顶点 //c(in):两个顶点间的距离 bools[n]; // s[i]表示该点是否在最短路径已知的顶点集合内。 for(inti=0;i<n;i++) s[i] = false; for(inti=0; i<n; ++i) { dist[i]=c[v*n+i]; if(dist[i]==INF) prev[i] = -1; else prev[i]=v; } //addv to s dist[v]= 0; s[v]= true; for(inti=1; i<n; ++i) { T_ dist_tmp = INF; int u = v; //选出该次到v最短的点,该点不属于s for(int j=0; j<n; ++j) { if(s[j])continue; if(dist_tmp==INF|| dist[j]<dist_tmp) { dist_tmp = dist[j]; u = j; } } s[u] = true; //加入该点后对其他点的影响 for(int j=0; j<n; ++j) { if(s[j]|| c[u*n+j]==INF) continue; T_dist_new = dist[u]+c[u*n+j]; if(dist_new<dist[j]){ dist[j]=dist_new; prev[j] = u; } } }} template<class T_>void Out(int n,int v,T_ dist[],int prev[]){ //n:(in)顶点数量 //v:(in)源顶点索引(0-...) //dist[]"(out)从源定点 到每个定点的距离 //prev[]:(out) 在最短路径上每个定点的前面的一个顶点 intpath_points[n*(n-1)/2+1]; inti,j,k; for(i=0;i<n; ++i) { if(i==v) continue; cout<<"顶点"<<i<<",最短路径长度="<<dist[i]<<endl; j=1; path_points[0] =i; k = i; while(prev[k]!=v && prev[k]!=-1){ path_points[j++]= prev[k]; k=prev[k]; } for(--j; j>=0; j--) { cout<<path_points[j]<<" "; } cout<<endl; } } int main() { intn=5; constfloat INF = 65535; floatdist[n]; intprev[n]; floatc[n*n]; constfloat graph_edges[] = { 0,10,INF,30,100, 10,0,50,INF,INF, INF,50,0,20,10, 30,INF,20,0,60, 100,INF,10,60,0 }; for(inti=0;i<n*n;i++) { c[i]=graph_edges[i]; } Dijkstra_ShortestPath<float>(n,0,dist,prev,c,INF); Out<float>(n,0,dist,prev); cin.get(); return0;}
Kruskal最小生成树
题目:
已知一幅图的顶点数n、边e以及边的权重w[i],求一权重最小的生成树。
算法思路分析以及相关数学公式:
将G的n个顶点看成n个孤立的联通分支,将所有边按权从小到大排序,然后依次增加权重最小的边来连接两个独立的联通分支,在加边时,注意不可以让加入的边在图中构成回路。
直至加入了n-1条边或者加入的边数为e。
另一种求最小生成树的算法是prim算法,他是从顶点的角度考虑。
//////////并差集实现//////////////////class CUnionFind {public: CUnionFind(); ~CUnionFind(); voidInit(int num_elem) ; intFindSubSet(int elem_id) ; voidSubSetUnion(int set1,int ste2);protected: intn_; //元素数量 int*parent_id_; //每个元素的父节点索引,-1表示该点为根节点 int*depth_; //每个元素所属子树的深度 voidRelease();}; void CUnionFind::Release() { n_= 0; if(parent_id_){ delete [] parent_id_; parent_id_ = NULL; } if(depth_){ delete [] depth_; depth_ = NULL; }} CUnionFind::CUnionFind() { n_= 0; parent_id_= NULL; depth_= NULL;} CUnionFind::~CUnionFind() { Release();}void CUnionFind::Init(int num_elem) { //元素编号从1开始 Release(); n_= num_elem; parent_id_= new int[n_]; depth_= new int[n_]; for(inti=0;i<n_;++i) { parent_id_[i]=-1; depth_[i]=0; }} int CUnionFind::FindSubSet(int elem_id) { //返回元素elem_id所属自己的编号 inti = elem_id-1; while(parent_id_[i]!=-1) i = parent_id_[i]; returni;}void CUnionFind::SubSetUnion(int set1,intset2) { //合并set1,set2 if(set1== set2) return ; if(depth_[set1]==depth_[set2]){ parent_id_[set2] = set1; depth_[set1]++; }else if(depth_[set1]<depth_[set2]){ parent_id_[set1] = set2; }else { parent_id_[set2] = set1; }}
class Edge{public: intweight; intu,v;};class cmp {public: booloperator() (Edge &a,Edge&b) { return a.weight > b.weight; }}; bool Kruskal(int n,int e,Edge E[],Edge t[]){ //n顶点数 //e边数 //E[]具体边 //t[](out)筛选出的边 priority_queue<Edge,vector<Edge>,cmp> q; for(inti=0; i<e; ++i) { q.push(E[i]); } CUnionFindU; U.Init(n); intk =0; while(e&& k<n-1) { //正常树应该会有n-1条边 Edge x; x = q.top(); q.pop(); e--; int a = U.FindSubSet(x.u); int b = U.FindSubSet(x.v); if(a!=b) { t[k++]= x; //cout<<"["<<x.u<<','<<x.v<<"]"<<endl; U.SubSetUnion(a,b); } } }void Out(int n,Edge t[]) { //n顶点数 //t[] 筛选出的边 for(inti=0;i<n-1;++i) { cout<<"["<<t[i].u<<','<<t[i].v<<"]"<<endl; }} int main() { intn = 6; EdgeE[10]; Edget[10]; E[0].u= 1; E[1].u = 1; E[2].u = 1; E[0].v= 2; E[1].v = 3; E[2].v = 4; E[0].weight= 6; E[1].weight = 1; E[2].weight = 5; E[3].u= 3; E[4].u = 5; E[5].u = 3; E[3].v= 2; E[4].v = 2; E[5].v = 4; E[3].weight= 5; E[4].weight = 3; E[5].weight = 5; E[6].u= 3; E[7].u = 3; E[8].u = 4; E[6].v= 5; E[7].v = 6; E[8].v = 6; E[6].weight= 6; E[7].weight = 4; E[8].weight = 2; E[9].u= 5; E[9].v= 6; E[9].weight= 6; Kruskal(n,10,E,t); Out(n,t); cin.get(); return0;}
- 算法篇-7-贪心算法-Huffman编码&Dijkstra单源最短路径&Kruskal最小生成树
- 贪心算法 最小生成树prim与单源最短路径dijkstra
- 贪心算法 - 最小生成树 Kruskal算法
- 贪心算法 - 最小生成树 Kruskal算法
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 【OpenSource】【图片加载】Google 推荐的图片加载开源框架 Glide
- 给samba的文件服务器启用回收站功能
- Android 技术之Glide和Picasso
- tomcat下配置https环境(windows环境)
- OAuth 2.0 授权原理
- 算法篇-7-贪心算法-Huffman编码&Dijkstra单源最短路径&Kruskal最小生成树
- Maven依赖之后Dubbo找不到依赖的facade
- 微信小程序-scroll-view滚动到索引位置(二)
- java中关键字volatile的作用
- springMVC源码分析--AbstractHandlerMethodMapping获取url和HandlerMethod对应关系(十)
- STM32在KEIL MDK环境下建立新工程
- 创建逆序输入值的单链表
- 数组中出现次数最多/最少的元素
- cocos2dx基础篇(23)——进度条CCProgressTimer