堆排序,Dijikstra算法和C#
来源:互联网 发布:常用的非线性优化算法 编辑:程序博客网 时间:2024/06/10 08:10
昨天搞了个通宵,总算把一堆与排序和图的算法用代码给实现了,其中最难的是堆排序和 Dijkstra 最短路径算法。今天早上扬眉吐气,以前望而生畏的东西,现在终于可以信手拈来了。
数组排序,以前我用快速排序,不过性能不太稳定,而且一不小心堆栈溢出。堆排序虽然比快速排序平均性能差点,但极端情况下要好得多,性能稳定。
经过测试,我的堆排序算法指令耗费为 75.66 N*log2 N,比快速排序平均性能 42.36 N*Log2N 要稍慢些,不过比冒泡法 10.32*N^2 要快许多了。也就是说,只要超过 17 个元素,则快速排序已经好于起泡排序;只要超过 39 个元素,则堆排序要好于起泡排序。
至于 Dijkstra 算法,以前上课也讲过,不过好象当时很难听懂。其实没什么难的,估计是那个老师不善于语言表达的缘故。实现起来其实也就一会的工夫。
先晾一下代码:
堆排序:
- public class HeapSortHeap {
- public int count;
- public int[] e;
- public HeapSortHeap(int count){
- this.count = count;
- e = new int[count+1];
- }
- public void HeapMake(int count){ //自上向下生成一个堆
- for (int i = count / 2; i > 0; i--) HeapAdjust(i, count);
- }
- //堆排序
- private void HeapAdjust(int idx, int count){ //自上向下调整一个堆
- for (int s = idx; s <= count / 2; ){
- int type = 0; int k = 0;
- if (e[s] < e[2 * s]) type |= 1;
- if (s < count / 2){
- if (e[s] < e[2 * s + 1]) type |= 2;
- if (e[2 * s] < e[2 * s + 1]) type |= 4;
- }
- switch (type){
- case 0: k = -1; break;
- case 1: k = 2 * s; break;
- case 2: k = 2 * s; break;
- case 3: k = 2 * s; break;
- case 4: k = -1; break;
- case 5: k = 2 * s + 1; break;
- case 6: k = 2 * s + 1; break;
- case 7: k = 2 * s + 1; break;
- }
- if (k >= 0){
- e[0] = e[s]; e[s] = e[k]; e[k] = e[0];
- s = k;
- }
- else return;
- }
- }
- public void HeapSort(){
- HeapMake(count);
- for (int i = count; i>=0; ){
- //1. 把最大的记录移到后面去
- if (e[1] < e[i]) { i--; continue; }
- e[0] = e[1]; e[1] = e[i]; e[i] = e[0];
- i--;
- //2. 对当前的堆进行调整
- HeapAdjust(1,i);
- }
- }
- }
Dijkstra 最短路径算法:
- public delegate void DiagramTranversHandler(int vindex,int parameter);
- class ArcDiagram {
- public int vcount; //点号从 1 开始
- public int[,] e; // -1 表示无路径
- //图的生成
- public ArcDiagram(int vcount){
- this.vcount = vcount;
- e = new int[vcount,vcount];
- for (int i = 0; i < vcount; i++) for (int j = 0; j < vcount; j++) e[i, j] = -1;
- }
- public ArcDiagram Clone(){
- ArcDiagram g = new ArcDiagram(vcount);
- for (int i = 0; i < vcount; i++) for (int j = 0; j < vcount; j++) g.set(i + 1, j + 1, e[i, j]);
- return g;
- }
- //Dijkstra 算法
- public void Dijkstra(int v0, DiagramTranversHandler handler){
- v0--;
- int i,j,k,v;
- int[] D = new int[vcount]; bool[] S = new bool[vcount];
- //1. 设 D S 初始状态
- for (i = 0; i < vcount; i++) { S[i] = false; D[i] = e[v0, i]; }; S[v0] = true;
- while (true){
- //2. 取 vj
- int min = -1; v = -1;
- for (j = 0; j < vcount; j++) if (S[j] == false && D[j] >= 0 && (min < 0 || min > D[j])) { v = j; min = D[j]; }
- if (v >= 0) S[v] = true; else break;
- //3. 修改 V-S 上的 D
- for (k = 0; k < vcount; k++){
- if (S[k] == false && e[v, k] > 0){
- if (D[k] < 0 && D[v] + e[v, k] >= 0) D[k] = D[v] + e[v, k];
- else if (D[v] + e[v, k] < D[k]) D[k] = D[v] + e[v, k];
- }
- }
- //4. 重复
- bool continueexec = false;
- for (k = 0; k < vcount && continueexec == false; k++) if (S[k] == false) continueexec = true;
- if (continueexec == false) break;
- }
- for (v = 0; v < vcount; v++) handler(v + 1, D[v]);
- }
- }
这些代码都是用 C# 写的。虽然刚学 C#,但似乎已经觉得 C++ 有点老土了。写 C++ 我总没欲望写出如此规范的代码来。以前我不用 C# 是担心其执行效率,但经测试,C# 好象并不慢。我是用算圆周率的方法来测试的。
讲到算圆周率,不得不说这个公式(LaTex 格式)
/sum_1^/infinity /frac{1}{n^2} = /frac{/pi^2}{6}
据说当年伯努利不会算,交给欧拉,欧拉把结果给猜出来了。这个公式收敛得很慢,用它来验证代码效率正好。我用 DOS 汇编、Win32 汇编、C++ 和 C# 都实现了一遍。DOS 汇编的那个牵涉到虚 86 模式的效率问题,所以这里晾一下另外三种语言编出来程序的效率(做了多遍,只取最快的记录,以排除线程切换的影响):
算到 300000000,圆周率 3.14159264498239,
汇编语言: 5.521058 秒
C++: 5.359000 秒
C#: 5.250 秒
我本来是想看看 C# 比 C++ 慢多少,结果大吃一惊,C# 密集计算比 C++ 还快!难道是 C# 用了比 C++ 更先进的编译优化?看起来其执行时基本上都是本地代码,而不是 C# 反汇编文件中显示的那些中间代码。有高手说原因是缓存机制,不知道是不是 C# 虚拟机代码有实时本地化功能,每次本地化一堆邻近的代码?
可以看看我用汇编写的代码,我感觉已经没有优化的余地了:
- mov i,1
- fldz
- mov edx,300000000
- LabelMain1_1:
- cmp i,edx
- jge LabelMain1_2
- fild i
- fimul i
- fld1
- fdivr
- fadd
- inc i
- jmp LabelMain1_1
- LabelMain1_2:
- mov i,6
- fimul i
- fsqrt
- fstp pi
在数据面前,我已经感觉,我的手动代码优化基本上没有意义了。记得以前写一个像素拷贝,指令段的优化最理想的情况下能提高 10% 的效率,但数据局域化程度却使程序效率在 100 倍的范围内变化。
最后,记得以前数据结构老师告诉,汇编语言不能做数据结构,那时起我才开始学习 C 语言,才第一次真正接触高级语言。然而后来,我不仅用汇编语言编出了动态内存管理,而且什么链表、队列、树、森林、哈希表,我都用汇编语言实现了,而且几乎天天用。虽然那位老师说得不对,不过我还是感谢他逼我学了一门高级语言。现在我已经很久没用汇编了,昨天乍一用连双内存寻址指令不存在都忘了。
- 堆排序,Dijikstra算法和C#
- 【算法】堆和堆排序
- 排序算法之堆和堆排序
- 排序算法—堆和堆排序
- 排序算法-快速排序和堆排序
- 快速 和堆 排序算法
- 堆排序算法(C#实现)
- Python算法 插入排序和堆排序
- 插入排序和堆排序算法
- 堆排序算法算法思想和程序
- Java排序算法--建立堆和堆排序(转)
- Java排序算法--建立堆和堆排序(练习)
- 建大顶堆和小顶堆及堆排序算法
- 【算法导论】堆排序和优先级队列
- 算法三:树和堆排序
- 【数据结构和算法16】堆排序
- scala数据结构和算法-08-堆排序
- 《算法导论》堆排序和优先队列
- c# 在mono上的移植 系列之一 邮件发送不工作了
- 一个很难想到的引起ORA-12154的原因
- .net web开发平台可行性
- asp 弹出窗口脚本函数
- distinct在JSP中的运用问题
- 堆排序,Dijikstra算法和C#
- jsp request 传递对象和其它数据 request.setattribute request.getattribute
- 编辑部的故事之二“骆记”的旁白-www.51cf.org
- 为什么陆涛不爱米莱……很经典 很深刻
- c# Web Services学习笔记(三、SOAP消息交换模型)
- 数据库中视图的作用
- 防止帐户密码被木马盗取的小办法
- asp 获取字符串长度函数
- 学习观察者模式的一个例子