您的位置:首页 > 其它

算法篇-7-贪心算法-Huffman编码&Dijkstra单源最短路径&Kruskal最小生成树

2016-12-27 21:51 567 查看
本系列所有代码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
;
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
; // 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
;
intprev
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐