【实习记】2014-08-27堆排序理解总结+使用typedef指代函数指针

过程记录

4个月前C语言版的七大排序算法实践让我在写C++版时轻车熟路。特别是冒泡,插入,希尔,选择这四种排序不用调试即运行成功。
输出的效果与C语言做的版本完全一样,其中令我印象深刻的是,cout对浮点的处理远不如printf简单明了。非常让开发者难受。

写C++版时有所改进。

#define sortfunc _selsort

可以用

typedef void (*sort_t)(vector<int>& arr);
sort_t sortfunc = _selsort;

两句代替。
也缩短了把函数指针作参数书写的长度。

很奇怪,又发现C语言版的堆排序是有问题的。
这次先把C++版堆写对了再回头写C语言版。写完后对堆理解加深不少。

堆具有几点性质:

1、任意arr[i/2]<= arr[i]。
2、堆顶元素最小。
3、堆对应数组下标为1..n。
4、最坏插入删除一个元素只需log2n,构造堆最坏nlog2n时间,但是处理平常输入的数据通常不如快速排序。

堆排序算法:

1、待排序目标是arr[1]到arr[n]
2、造堆
    a)前n-1号已经满足堆性质。增加一个n号,移动n号造堆,使得前n号为止都满足堆。
    b)考虑n/2,n(如果n是奇数则考虑n/2,n,n-1),交换n与n/2或交换n-1与n/2,使得n/2最小。(注:n/2总是整数)
    c)若b)没交换,到d);若b)发生交换,使n=n/2,重复b)操作。
    d)前n号满足堆,使n=n+1,重复a)操作直到成功。
3、尖堆
    a)1到n号具有堆性质,所以1号最小,交换1和n号并移动1号使1到n-1号重新恢复堆。
    b)j=1,考虑j,j*2,j*2+1,交换j与j*2或交换j与j*2+1使得j最小。
    c)若b)没交换,到d);若b发生交换,j=j*2(或j*2+1,看交换的是哪个),重复b)。
    d)1到n-1号具有堆性质,使n=n-1,重复a)。
4、反序
5、arr[1]到arr[n]已排序
(以上算法描述个人原创,代码虽易,描述不易,且描且珍惜……)

C++的(vector)版

void _hsort(vector<int>& arr, int len){
    // vector<int> arrtmp (len+1);
    arr.resize(len+1);
    int i,j,k;
    // 右移一位
    for (i=len;i>=1;i--)    // bug! i>1
        arr[i] = arr[i-1];
    // 造堆
    for (i=2;i<=len;i++){
        /* 这种就是用while比for好
        for (j=i/2;j>1 && arr[j]<arr[j/2];j/=2)
            swap(arr[j], arr[j/2]);
          */
        j = i;
        while (j>1){
            k = j/2;
            if (j%2 && arr[j-1]<arr[j])
                j -= 1;
            if (arr[j]<arr[k])
                swap(arr[j], arr[k]);
            j = k;
        }
    }
    // 交换头尾,恢复推性质,直至反序排列
    for (i=len;i>1;i--){
        swap(arr[1], arr[i]);       //bug! 现在只要回复1到i-1的堆性质,而不是到i
        j = 1;
        while (j<i-1) {
            k = j*2;
            if (k>i-1)
                break;
            // 小的先上,冒泡味道
            if (k+1 <=i-1 && arr[k] > arr[k+1])
                k += 1;
            if (arr[j]>arr[k])
                swap(arr[j], arr[k]);
            j = k;
        }
    }
    // 反序
    i=1;j=len;
    while (i < j){
        swap(arr[i], arr[j]);
        i++;j--;
    }
    // 复位
    for (i=0;i<len;i++)
        arr[i] = arr[i+1];
    arr.resize(len);
}

C语言版

void _hsort(int arr[], int len)
{
    int i,j,t;
    /*int *arrtmp = (int*)malloc((len+1)*sizeof(int));
    for (i=0; i<len; i++)
        arrtmp[i+1] = arr[i];*/
    int *arrtmp = arr-1; /*处理技巧:这样就不用额外内存,注意不要用arrtmp[0];*/
    /* make heap */
    for (i=2; i<=len; i++){
        /* shift up 以保持堆性质 */
        j=i,t=j/2;
        while (t>=1){
            if (j%2 && arrtmp[j]>arrtmp[j-1])
                j -= 1;
            if (arrtmp[t]>arrtmp[j])
                swap(arrtmp[t], arrtmp[j]);
            j=t,t=j/2;
        }
        /*t = i/2;
         *while (t>=1 && arrtmp[t]>arrtmp[i]){
         *    swap(arrtmp[t],arrtmp[i]);
         *    i = t, t = i/2;
         *}
         * Bug!
         * while循环见鬼了:
         * 1、去掉swap句会死循环,2、平方时间。
         * gdb display t 跟踪,t值变化很吓人。
         * 找3小时同时gdb display i才找到原因:i=t,t=i/2;改变了外层for的i递增。相当隐秘。
         */
    }
    /* 排序后是逆序的 */
    for (i=len; i>=2; i--){
        swap(arrtmp[i], arrtmp[1]);
        /* shif down */
        j = 1, t = j*2;
        while(t<i-1){
            if (t+1<i && arrtmp[t]>arrtmp[t+1])
                t += 1;
            if (arrtmp[t] < arrtmp[j])
                swap(arrtmp[t], arrtmp[j]);
            j = t, t = 2*j;
        }
    }
    i=1,j=len;
    while (i<j)
    {
        swap(arrtmp[i], arrtmp[j]);
        i++; j--;
     }   /* bug!! arrtmp[i++] = arrtmp[j--]; */
    /*for (i=0; i<len; i++)
        arr[i] = arrtmp[len-i];
    free(arrtmp);*/
}

技巧

一、传入的数组指针有效下标一般是0到n-1,而堆排序要求下标是1到n。
    解决方法:新建指针变量指向传入指针的前一个位置,操作新指针即可。
    原来的方法:申请内存,错位复制过去,排序后复制回来。

git记录

发现_hsort函数问题

从master的某个提交checkout,然后git branch 建立分支, 再checkout到分支

在分支上修复成功后git rebase都几个分支上,出现冲突,解决,继续,因为冲突,git log显示之前的提交时间都被修改了。

所以应该用git merge比较好。

时间: 2024-10-13 00:57:19

【实习记】2014-08-27堆排序理解总结+使用typedef指代函数指针的相关文章

【实习记】2014-08-10(下)用宏来批量声明定义函数

(冒泡,选择,插入,希尔,快速,归并,堆排)周末加班学习C++,打算用C++写七大经典排序代码. 之前写好的C实现代码debug后运行良好.之前的mysortlib.c中函数声明如下,接口完全是一样的. void _bubsort(int arr[], int len); void _bubsort_(int arr[], int len); void _isort(int arr[], int len); void _isort_(int arr[], int len); void _ssor

2014/08/27

转眼间,周三了有木有,时间过的可真快,不过这周有六天要上班,所以还有整整四天的上班时间,这段时间过的有点慌里慌张,迷迷糊糊的起床,上班下班,回去后看看电视,依然很累,然后睡觉质量也不好,大多时间处于似睡似醒的状态,这大概是缺乏锻炼的缘故吧! 下周一刚好九月一日,从那天起,开始新的计划,上班期间努力工作,不开小差,下班后锻炼身体,再忙再累再多借口也得完成计划好的,PLANK.俯卧撑.引体向上.卧推.仰卧起坐都得有,循环渐进,周末上淘宝淘副哑铃,现在的重量不够刺激O(∩_∩)O 昨天接到一个活,要对

2014/07/27

这个时候的天气,总是阴晴不定,而且闷热到心情压抑.今天无所事事,除了看新闻了解一点实事外,其他时间都用来上网看视频.聊天,写的实习计划落下两天的时间了,明天加把劲把落下的学习补回来. 2014/07/27,布布扣,bubuko.com

记2014年暑假,一个项目,三个框架

在开始动笔之际,看了下博文的标题,突然觉得欠妥,"记2014年暑假,一个项目,三个框架",既然是暑假说明还是学生,今年的6月我已经毕业了,但还在学习,并且在向一名合格的架构师狂奔.你说我矫情也好,做作也罢,现实就是这样的,厚着脸说:咱也矫情一回. 整个暑假,总共四十天,从7月中旬开始到8月底,从技术上看,整个假期都处于看视频,做项目,作总结的过程中,前二十天跟着视频做了DRP的项目,后二十天(到8月26日),看完了三个框架的视频,总结还在继续:从英语上看,这个假期是从听走向说的开始:从

记2014英特尔杯嵌入式邀请赛

2014年Intel杯大学生电子设计竞赛嵌入式邀请赛已经圆满结束了,我很高兴能够捧得最高奖Intel杯.自从捧杯的这几天来,各路媒体的采访,学校的祝贺,同学好友的祝贺应接不暇,对此我也表示非常感谢.作为一名大学生,我很明白这个“光环”所带来的也就是这几天的关注而已,而最终也将被请下神坛,继续做我的一位平凡大学生.收获也不能说没有,但收获并不是别人给的,是需要自己去寻找,自己去总结的. 回想六个月的项目经历,可以说是曲折坎坷,又有点神奇美妙,仿佛上帝安排.项目的第一阶段是构思创意,真正的想创意时间

记2014“蓝桥杯全国软件大赛&quot;决赛北京之行

5月29,30日 终于到了这一天.晚上有数据结构课,10点多的火车,我们就没有去上课,下午在宿舍里收拾东西,晚上8点左右从南校出发,9点半多到达火车站和老师学长学姐们会和. 第一次去北京,第一次买的卧铺,真的很兴奋.对这次北京之行满满的都是期待.卧铺,躺在上面很舒服,因为第一次,不知道还需要换票,就把票放在包里了,找了一会才找到,看来还是得把票随身带着.卧铺晚上熄灯,我看了一部电影,然后就睡着了,一觉睡到五点多.上午看了看模板,这次蓝桥杯决赛说实话没有怎么认真的准备,做的题也比较少.把一些小的知

Bootstrap 3.2.0 源码试读 2014/08/09

第一部分 normalize.css 104至110行 code,    /* 编辑代码 */ kbd,    /* 键盘输入的文本 */ pre, samp {    /* 范例,sample的简写 */   font-family: monospace, monospace;    /* 这个地方应该是写错了,第二字体应该是serif */   font-size: 1em; } 设置字体的大小为1em,字体为monospace. 111至119行 button, input, optgro

在MyEclipse配置自己安装的Tomcat(2014.08.18)

今天因为要在tomcat下运行一个java项目,第一次嘛,遇到了不少问题,总结分享一下: 第一次,我直接将 MyEclipse 生成的项目放到 tomcat 安装目录的 webapps 目录下,运行出现404,无法访问. 然后想了想,发现这是个错误的做法.应该先通过 MyEclipse 将项目部署到 Tomcat 下: 然后, MyEclipse 自带了 tomcat,我要配置自己安装的 TomCat : (请看参考资料:http://jingyan.baidu.com/article/4853

X100S Collection Before 2014/08/01

风暴前的东京湾 // Tokyo Bay before Storm 上野公园 // Ueno Park X100S Collection Before 2014/08/01,布布扣,bubuko.com