排序
1. 直接插入排序
原理:将当前无序区a[i...n-1]的记录一个一个插入到有序区a[0....i-1]合适位置;
1 void insert_sort(int a[], int n) 2 { 3 int j; 4 for(int i=1;i<n;i++) 5 { 6 int temp=a[i]; 7 8 for(j=i-1;j>=0&&temp<a[j];j--) 9 { 10 a[j+1]=a[j]; 11 } 12 a[j+1]=temp; 13 } 14 }
2. shell 排序
原理:实质为分组插入排序,首先按增量为d分成若干组,下标相差d的元素放在一组使用直接插入排序;然后用一个较小的增量继续分组和排序,直至增量减到1,整个分组即为一组,排序完成。
1 void shell_sort(int *a, int n) 2 { 3 for(int h=n/2;h>0;h=h/2) 4 { 5 for(int i=h;i<n;i++) //for 循环就是增量为h的直接插入排序 6 { 7 int temp=a[i]; 8 int j; 9 for(j=i-h;j>=0&&temp<a[j];j=j-h) 10 { 11 a[j+h]=a[j]; 12 } 13 a[j+h]=temp; 14 } 15 } 16 }
3. 冒泡排序
原理:首先将a[0...n-1] 垂直排列,根据气泡原理,较轻的会浮在较重的上面。 自底向上扫描:凡扫描到违反此原则的轻气泡,就使其上浮。
每遍扫描都会是最轻的一个元素上浮。扫描n-1 趟
1 void bubble_sort(int a[],int n) 2 { 3 for(int i=0;i<n-1;i++) 4 { 5 for(int j=n-1;j>i;j--) 6 { 7 if(a[j]<a[j-1]) 8 { 9 int temp=a[j]; 10 a[j]=a[j-1]; 11 a[j-1]=temp; 12 } 13 } 14 } 15 }
4. 快速排序
快速排序是一种交换排序,采用的了“分治”的策略。
分治法的哦基本思想是: 将原问题分解为若干个规模更小但结构和原问题相似的子问题,递归解决这些子问题,然后将这些子问题的解组合为原问题的解。
快速排序基本思想:将当前无序区A[low...high],采用分治法描述为:
(1)分解:在A[low...high]中选用一个元素作为基准(pivot),以此基准将A[low...high]划分为两个左右区间A[low...pivot-1],A[pivot+1...high]。使得左区间都小于A[pivot],右区间都大于A[pivot]。即A[low...pivot-1]<=A[pivot]<=A[pivot+1...high]。
(2)求解:递归对左右区间进行快速排序。
(3)组合:递归做完,其区间即为有序。
1 void quick_sort(int a[],int low, int high) 2 { 3 int i,j,pivot; 4 if(low<high) 5 { 6 pivot=a[low]; 7 i=low; 8 j=high; 9 while(i<j) //终止的条件极为i=j 10 { 11 while(i<j&&a[j]>=pivot) 12 j--; 13 if(i<j) 14 a[i++]=a[j]; //将比pivot小的元素移到低端 15 16 while(i<j&&a[i]<=pivot) 17 i++; 18 if(i<j) 19 a[j--]=a[i]; //将比pivot 大的元素移到高端 20 } 21 a[i]=pivot; 22 quick_sort(a,low,i-1); 23 quick_sort(a,i+1,high); 24 } 25 }
5. 直接选择排序
基本思想:有序区A[0...i-1]和无序区A[i...n-1]。在无序区A[i....n-1]中选择一个最小的元素与A[i]进行交换,有序区增加1 为A[0....i]。
1 void select_sort(int a[], int n) 2 { 3 int i,j,l,min; 4 for(i=0;i<n-1;i++) //遍历n-1遍 5 { 6 int min=a[i]; 7 int l=i; 8 for(j=i;j<n;j++) 9 { 10 if(a[j]<min) 11 { 12 min=a[j]; 13 l=j; 14 } 15 } 16 a[l]=a[i]; 17 a[i]=min; 18 } 19 }
6. 堆排序
堆排序是利用的堆的特性进行排序的一种排序方法。
堆是一个完全二叉树,分为大根堆和小根堆。
在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
既然是堆排序,首先就要建堆,而建堆的核心是调堆,使满足堆的特性。调堆首先从最后一个非叶子节点开始,假设有数组A = {1, 3, 4, 5, 7, 2, 6, 8, 0}。那么调堆的过程如下图,数组下标从0开始,A[3] = 5开始。分别与左孩子和右孩子比较大小,如果A[3]最大,则不用调整,否则和孩子中的值最大的一个交换位置,在图1中是A[7] > A[3] > A[8],所以A[3]与A[7]对换,从图1.1转到图1.2。
1 int heapSize=0; //堆大小 2 int leftChild(int index) 3 { 4 return (index<<1)+1; //下标从0开始 5 } 6 int rightChild(int index) 7 { 8 return (index<<1)+2; 9 } 10 void maxHeapify(int a[],int index) //调整堆,index 表示堆顶索引 11 { 12 int largest=index; //最大索引 13 int left=leftChild(index); //左子节点索引 14 int right=rightChild(index); //右子节点索引 15 if(left<heapSize&&a[left]>a[largest]) 16 largest=left; 17 if(right<heapSize&&a[right]>a[largest]) 18 largest=right; 19 20 if(largest!=index) 21 { 22 swap(a[index],a[largest]); 23 maxHeapify(a,largest); //新父节点,递归调整堆 24 } 25 } 26 void buildMaxHeap(int a[], int length) 27 { 28 heapSize=length; 29 int begin=length/2-1; 30 for(int i=begin;i>=0;i--) 31 { 32 maxHeapify(a,i); 33 } 34 35 } 36 37 void heap_sort(int a[],int length) 38 { 39 int i; 40 buildMaxHeap(a,length); 41 for(i=length-1;i>=1;i--) 42 { 43 swap(a[0],a[i]); //堆顶a[0]为最大元素,被换至数组尾部a[i] 44 heapSize--; //从堆中移除该元素 45 maxHeapify(a,0); //重建堆 46 } 47 }
7. 归并排序
自顶向下解法:
(1)分解:将当前区间一分为二,求分裂点;
(2)求解:递归对两个子区间A[low...middle]和A[middle+1, high]进行归并排序;
(3)组合:将以排好序的两个子区间进行合并为一个有序的区间A[low...high];
(4)递归的终止条件,字区间长度为1;
1 /***********归并排序************************/ 2 void merge(int a[],int tmp[],int lPos,int rPos,int rEnd) 3 { 4 int lEnd=rPos-1; 5 int tmpPos=lPos; 6 int elemNum=rEnd-lPos+1; 7 while(lPos<=lEnd&&rPos<=rEnd) 8 { 9 if(a[lPos]<a[rPos]) 10 tmp[tmpPos++]=a[lPos++]; 11 else 12 tmp[tmpPos++]=a[rPos++]; 13 } 14 while(lPos<=lEnd) 15 tmp[tmpPos++]=a[lPos++]; 16 while(rPos<=rEnd) 17 tmp[tmpPos++]=a[rPos++]; 18 for(int i=0;i<elemNum;i++,rEnd--) 19 { 20 a[rEnd]=tmp[rEnd]; 21 } 22 } 23 void msort(int a[],int tmp[],int low,int high) 24 { 25 if(low<high) 26 { 27 int middle=(low+high)/2; 28 msort(a,tmp,low,middle); 29 msort(a,tmp,middle+1,high); 30 merge(a,tmp,low,middle+1,high); 31 32 } 33 } 34 void merge_sort(int a[], int len) 35 { 36 int *tmp; 37 tmp=new int[len]; 38 if(tmp!=NULL) 39 { 40 msort(a,tmp,0,len-1); 41 delete []tmp; 42 } 43 }
8. 基数排序
基数排序是桶排序的延伸和改进。
于两种不同的排序顺序,我们将基数排序分为LSD(Least significant digital)或MSD(Most significant digital),
LSD的排序方式由数值的最右边(低位)开始,而MSD则相反,由数值的最左边(高位)开始。
LSD算法如下:
1 /******************基数排序********************/ 2 int get_kthDigit(double number,int k) //获取第k 位的数值 3 { 4 number/=(int)pow(10.0,k); 5 int res=(int)number%10; 6 return res; 7 } 8 int get_max(int a[],int len) //最大值 9 { 10 int max=a[0]; 11 for(int i=1;i<len;i++) 12 { 13 if(max<a[i]) 14 max=a[i]; 15 } 16 return max; 17 } 18 int get_digitNumber(int number) //计算位数 19 { 20 int digit=0; 21 while(number) 22 { 23 number/=10; 24 digit++; 25 } 26 return digit; 27 } 28 void radix_sort(int a[],int len) 29 { 30 int count[10]={0}; 31 int *temp[10]; 32 for(int i=0;i<10;i++) 33 { 34 temp[i]=new int[len]; 35 memset(temp[i],0,sizeof(int)*len); 36 } 37 int max=get_max(a,len); 38 int maxDigit=get_digitNumber(max); 39 for(int i=0;i<maxDigit;i++) 40 { 41 memset(count,0,sizeof(int)*10); 42 for(int j=0;j<len;j++) 43 { 44 int x=get_kthDigit(a[j],i); 45 temp[x][count[x]]=a[j]; 46 count[x]++; 47 } 48 int index=0; 49 for(int j=0;j<10;j++) 50 { 51 for(int k=0;k<count[j];k++) 52 a[index++]=temp[j][k]; 53 } 54 } 55 }