八大算法的user story

2014.6.30
好久没有编程了,连个冒泡都不会了。勉勉强强编了一个没有flag的,明天考虑加个flag。
连编译都不会了,起码搞了15分钟,⊙﹏⊙b汗!!!
今天用SecureCRT来远程登录自己的虚拟机了,高端!终于在自己的机子实现小黑窗了!




2014.7.1
今天来学校学编程,看了大绿书后,终于搞清楚flag怎么加,原来跟我想的完全不一样,
这个算法是要后向驱动,把最小的筛选到i的位置。加flag的目的是一篇j扫描,如果没有互换,说明所有的a[j-1]<a[j],那么还要搞个毛,全部排好了呀!
今天有搞了个简单选择,完全忘了,有点跟直接插入搞。
这个算法是第一次用k=i代表最小的,后面发现小的j,就用k替换掉,然后后面的j都跟这个k比较,使得k永远保持最小的,
在一遍j扫描完后,把k标记的数給a[i].
今天真是觉得自己太睡了,本来半个小时能码7个算法,现在一个小时搞一个都够呛
哎。。。继续努力!!




2014.7.8
直接插入算法:假设前i个数字已经按序排列(默认1个),单独取出第i+1位置的数。将他一次与前i个数逐个进行比较,
如果发现比前边一个数小,那么前面一个数就用覆盖的方式后移一位,相应地留出了一个空档。然后再与更前面的数比较,都小的话,发现空档
在不断往前移,直至遇到比这个单独取出的数大的,相当于撞墙了。那么就把这个数放到最近的空档里。
但是这个空档是在你所遇到的墙的后面一位。相当于墙后面的一个坑,其实这个坑一直在等你撞墙!
当我停下来的时候,我不是在坑的位置,而是在坑前面的位置,如果想到掉进坑,我就要向后右移一位。!
移位的要求很苛刻,必须是单独取出的数小于前面的数,如果遇到墙了或者到头了,我就break
j的位置是墙的位置,如果经判断,j的位置不是墙,那么就要在j的位置上挖个坑,把当前的东西移到后面去,a[j+1]=a[j].
********************************************************************************************************************************
堆排序:堆排序实际上是用大根堆的方式,将一棵树,分为若干个单元,每个单元由两个(一个)叶子和一个root组成。
大根堆就是指单元中的root相较于单元中的叶子,是最大的。在树中,某个单元的root,可能也是其他单元的叶子。

若一棵树有n个节点,那么前n/2个都不是叶子,或者说是某一单元的root。
把每个root依次挑出,在这个root的单元里,从root和叶子中,挑出最大的,作为root。
在挑的过程中,*先判断左子树是否存在*,如果存在,说明这个root是真root,而不是叶子。
随后判断这个单元右子树是否存在,左子树是2*root,那么右子树是2*root+1,如果右子树存在,将左右子树分别比较,找出最大的数,跟root比较。
如果root小于较大的叶子,那么就把大叶子作为root。
注意:原本的叶子可能是某一单元的root,在与本单元的root互换后,那么原单元相当于换了一个root。而这个新root可能小于新单元的叶子。
所以在对需要将本单元排序后,应对因此被破坏的单元进行重新排序。那么新单元root的位置是本单元新root的原始位置。
如果在root与叶子比较过程中,没有出现互换的情况,那么说明这次挑出的root是大根,并且没有破坏到其他的单元,所以此次排序完成。继续下一个单元root的迭代。
当所有单元root全部迭代后,能够保证,整棵树中,树的root是最大的。并且保证,每一层root,都是比下一层的root或叶子大。
迭代的目的:一次调整只是深度遍历,而不是广度,因此需要迭代,才能面面俱到。
构建数完成!
那么我们就将树的root,即a[0],放到数组最后一个中.也就是放到第n个位置。而原本的a[n],放到了root的位置,即原本的大根数被破坏了,
所以我们需要从0开始,将被破坏的那一脉,重新构建。不是广度调整,而是深度调整。
然后我们从0 - n-1之间(去除了已经排好的旧root),重新按照上述繁琐的方式,构建一次大根树。再找出树的root,放到数组的倒数第二个。
那么每次构建一次树,都能找出一个最大的数,而树的规模比前一次构建完成,总数都少1.直至只有root,没有叶子。


2014.7.15
归并排序:归并排序原理是将一个数组,按照一个长度分割为若干个单元,然后相邻的两两单元,按照大小关系,进行排序,即两个单元按照顺序进行合并。当所有相邻的两两单元都归并好了,
那么把整个数组存放到一个辅助内存中,将单元长度翻倍,再一次分割数组,然后相邻的两两单元再进行归并,再存入原来的内存中,直至单元长度大于数组长度为止。

首先要申请一个辅助内存,设定初始单元长度(默认1),设定复制开关,0就是将原内存复制到辅助内存,1就是将辅助内存复制到原内存。
其次,就是将整个数组按照单元长度进行分割。首先,按照单位长度分割,查看时候有两个单元,如果有的话,就能进行合并了,如果没有,直接放到辅助内存中。
然后要计算出第一个单元的起点,终点,第二个单元的终点,或者说是合并后单元的终点。
如果计算得出的第二个单元的终点大于总长度了,说明第二个单元实际长度一定小于规定长度,所以需要将第二个单元的终点设置为数组最后一个的位置。
再分割完后,将相邻的单元分别取出,都从头开始,比较大小。将排序后的单元存放到辅助内存中。
单元都是两个两个取的,当前一对单元排序往后,整个数组还剩一个单元时,无法组成一队,那么就把它先放到辅助内存中,等待下一次排序。
每一次按照某个长度将整个数组合并处理后,必须将长度翻倍。
最后需要根据复制开关的值,判定是否需要将辅助内存数据放到原内存中。
********************************************************************************************************************************
快速排序:将一个数组的第一个数作为base,数组中大于base的放到右边,小于base的放到左边,
那么就会产生以base为界的两个单元:base左边的数组,包含base在内的右边的数组。
然后分别在左边和右边单元取第一个为base,又能分出4个子单元,直至一个某个子单元只有一个数位置,那么这一部分就结束了,
如果所有子单元都分割成只有一个了,即left=right,那么整个数组都排序好了。

那么怎么将一个数组(单元)中大于base的放到右边,小于base的放到左边呢?
首先,以第一个数作为base,left是数组头,right是数组尾,两个指针会朝中间移动。当两个指针不相遇,
先从右边开始,如果右边的大于base,那么说明正常,right会朝左边移动一位,继续寻找。直到right跟left相遇,或者遇到了右边的小于base的情况。
那么right位置的数,就会填到left位置上。就这样,一次right操作结束,接下来是left操作。
再从左边开始,如果左边的小于base,那么说明正常,left会朝右边移动一位,继续寻找。
由于上次right操作将小于base的数放到了left的位置,那么这次left位置的数必然是大于base的,所以第一次left操作是将;left向右移一位。
然后继续寻找,直到left跟right相遇,或者遇到了左边的大于base的情况。那么left位置的数,就会填到right位置上。就这样,一次left操作结束,接下来又是right操作。
两者反复操作,直至right跟left相遇后停止。
当我left与right碰头了,说明left在数组(单元)的中间,中间就应该放中间值,再将base交换给left的数,使得base的位置一直是中间的。
最后返回left位置,即数组的中间值位置。
随后的反复递归是避开i的,所以找到中间值,就相当于在数组中不断插入图钉,最后就在两个数中,有一个是图钉,那么另一个就孤零零地出现了!
********************************************************************************************************************************
链表排序:链表排序的每次读入一个数,就将数进行排序,而不是对一组数据进行处理,是一个一个处理的过程。
在排序过程中,每一次都要从链表头去开始向后搜索,所以在函数中定义head是不明智的,head需要不随函数变化。所以在主函数中就要定义head的。
在读入一个data后,就开始在链表中排序了。

我们知道,head指针是不放数据的,所以数据都是在head->next开始的。
p就是一个导游,如果导游到了NULL,或者导游所指的数据大于新来的数据,那么就要将新来的数据插入链表中了。
新建一个节点,存入数据,后接入导游节点,前接入前节点,完成!
如果上述两个都没达到,那么导游的前指针和导游本身,都要后移,继续寻找。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值