排序方法(一)
2016-05-14 23:16
274 查看
参考
参考
冒泡排序
原理
比较相邻两个元素的大小,进行调整位置。代码
略。快速排序
原理
通过一次排序将数据分成两个独立的部分,再分别对两部分进行排序,直到结束。代码
void quicksort(int a[],int left,int right){ if(right <= left){ return; } int i = right,j = left; int base = a[j]; while(i > j){ //开始从右往左寻找,寻找第一个比base小的数 while (i > j && a[i] >= base) { i--; } //从左往右寻找,寻找第一个比base大的数,同时不能寻出右指针的位置 while (i > j && a[j] <= base) { j++; } if(i > j){//如果各自寻找,交换两者位置 swap(a, j, i); } } if(j == i){//两者重逢,交换重逢位置与基数 swap(a, left, j); quicksort(a, left, j-1);//对左右两个数组进行快速排序 quicksort(a, j+1, right); } }有一点需要说明:上例是从小往大排序的,所以必须先从右往左开始寻找,内部的两个循环的顺序不能交换,如果从大往小排序,则两个循环的顺序必须换过来。假如对10,0,11进行从小往大排序,并且交换两个循环的位置,那么i = j时两者都指向的了11,然后将10与11进行交换,很明显不符合排序要求。
堆排序
原理
先将数据排列成一个大顶堆或小顶堆,然后将根结点与最后一个交换,这样就将最大数或最小数放到了数组的末位。依次进行,走到排完整个数组即可。堆是一个完全二叉树,序号为k的节点的左右子节点的序号为2k,2k+1。
代码
//调整i元素的位置,以确保生成的堆是最小堆 void siftdown(int h[],int i,int n){ int pos = i; while(i*2 <= n){//有左子树 int root = h[i]; if(root < h[2*i]){//比左子树值小 pos = i; }else{//比左子树的值大,但也不需要现在交换位置,因为可能右子树的值更小 pos = 2*i; } if(2*i+1<=n){//有右子树 if(h[2*i+1] < h[pos]){//右子树的值更小 pos = 2*i + 1; } } if(pos != i){//需要调整位置 swap(h, pos, i); i = pos;//判断调整到新位置后,要不是仍旧需要调整 }else{//不需要调整位置,所以结束循环 break; } } }上面方法只是对某个位置的元素进行调整,以使其符合最小堆的要求。故而只要使用一个循环,将所有的元素都进行调整即可。
这里还应该意识到,所有的叶子节点是不用进行往下调整的,因为它没有子节点。故而循环开始的位置应该是最后一个叶子结点的父结点。
在循环过程中,会采用从后往前,这是因为如果从根结点开始的话,并不能保证新调整到根节点上的元素是最小元素(因为还有很多元素没有进行比较)。代码如下:
int main(int argc, const char * argv[]) { int num = 9; int a[] = {0,10,1,100,20,4,354,43,18,0};//注意a[0]不用 int x = 0; for(x = num /2;x>=1;x--){ siftdown(a, x,num);//先将数组构成小顶堆 } while(num >= 1){ printf("%d ",a[1]);//输出最小的.也可将该值存储起来, a[1] = a[num]; num--; siftdown(a, 1,num);//将最后一个值移动到第一个位置后,需要判断该位置是否需要再进行调整 } }
选择排序
原理
先找到序列中最小值(或最大值)于序列中的第一个元素交换,这样就将最大值或最小值放到了最前面;再从剩余部分(除了第一个元素之外的部分)中找到最大(小)值与第二个元素交换,依次类推,直到序列结束。选择排序即是选择最大或最小的元素按放在已排序完成的队列的末尾。
代码
void selectsort(int a[],int count){ int x = 1; for (x =1; x<=count; x++) { int index = x; int j = x+1; for(;j<=count;j++){//从当前元素的下一个元素进行遍历 if(a[j] < a[index]){//如果有比当前还小的,则记录位置 index = j; } } if(index != x){//最小的不是当前元素,所以把当前元素与最小的元素进行交换 swap(a, x, index); } } }
插入排序
原理
将序列分为已排序(初始时只有序列的第一个元素)与未排序两部分,取未排序的第一个元素与已排序的最后一个元素比较,如果前者小,则将前者往前移(即将未排序的首位的值换成已排序的末尾值);再与已排序的倒数第二个进行比较,如果前者小,则将已排序的末尾值设置成已排序的倒数第二位值。依次类推,直到找到比未排序的首位小的位置或者已排序序列的首位。经上面操作后,就将未排序的首位放入到了已排序中的合适位置。然后进行下一个循环即可。
代码
void insertsort(int a[],int count){ int x = 1; for(x = 0;x< count-1;x++){ int j = x+1; int value = a[j]; while(value < a[j - 1] && j>0){ a[j] = a[j-1];//用前一位的值为后一位赋值,就相当于把数值整体往后移了一位。而多余的空位就是用来插入value的。 j--;//j始终指向的是当前value要插入的位置的下标 } a[j] = value; } }
归并排序
原理
将序列沿中间坐标分为两组,分别对两种进行归并排序,最后将排序完毕的两组合并成一组,这组就是已经排序好的结果。在不断分组的过程中,最终会分到一个组只有一个元素的情况下,此时就不需要进行排序,直接进行合并即可。这也保证了方法递归终有结束的时候。
代码
void merge_sort(int a[],int start,int end){ if(start < end){ int min = (start+end)/2; merge_sort(a,start,min); merge_sort(a,min+1,end); merge(a,start,min,end); } }
上述代码会将序列进行分组排序,并调用merge进行合并。merge代码如下:
//合并两个分组 void merge(int a[],int start,int mid,int end){ int b[end-start+1];//用于临时存储合并后的数据 int i = start,j = mid+1; int index = 0; while(i <= mid && j<=end){ if(a[i] < a[j]){ b[index] = a[i]; i++; }else{ b[index] = a[j]; j++; } index++; } while(i<=mid){ b[index++]=a[i++]; } while(j<=end){ b[index++]=a[j++]; } i = start; for(index = 0;i<=end;index++,i++){ a[i] = b[index]; } }
希尔排序
参考原理
先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。下标为k的元素与k+gap,k+2*gap……等为一组,对每一组进行插入排序,并且随着gap的缩减不断进行排序。这样序列会越来越有序,相应地插入排序的效率会越来越高。
其本质为:先分组,利用插入排序减少内部无序化,在整体进行一次插入排序。相当于先把一个大的数组分成几个小的数组插入排序,减少小数组中每个元素遍历次数提高在小数组中插入排序的效率。小数组有序后,再进行合并,这样就能提高大数组的有序性,进而提高对大数组执行插入排序的效率。
代码
void she b41e llsort(int a[],int count){ int gap = 0,j; for(gap = count /2;gap>0;gap /=2){ for(j = gap;j<count;j++){ if(a[j] < a[j-gap]){ int value = a[j]; int k = j-gap;//k表示当前元素value的前一个位置 while(k>=0 && value<a[k]){ a[k+gap] = a[k]; k -= gap; } a[k+gap] = value; } } } }上述代码的主要逻辑为:从gap处的元素进行同组插入排序,直到执行到序列的最后一个元素。
相关文章推荐
- PAT L1-6 最长连续因子
- C#.NET MVC 枚举转dictionary自动装载生成下拉框
- MySql Service 安装流程,包含解决服务无法启动 服务没有报告任何错误
- NYOJ squares(计算几何+区间覆盖)
- 转Linux下C编程实现之文件系统
- Lucene.net
- JAVA实现冒泡排序和二分查找
- NET5
- Jmeter--EN5并发测试遇到问题点
- 单页应用Scrat实践
- Java 之反射
- WEB服务器、应用程序服务器、HTTP服务器有何区别?
- 程序员必须知道的10大基础实用算法及其讲解
- LeetCode 292. Nim Game
- 蓝桥杯:出现次数最多的整数
- 多线程----线程通信
- 记录
- 对照Java学习Swift--协议(Protocols)
- Linux stty命令
- EasyUI动态创建、删除模态Dialog