对各种排序的分析和实现

来源:互联网 发布:python 网页编码转换 编辑:程序博客网 时间:2024/05/25 19:55

插入排序:(假设是升序)

思路:假设有一个数组a[10] = {10,3,4,6,5,2,1,9,8,7} ,设置一个tmp,第一次值是a[1],因为tmp值小于a[0],所以把a[0]的值往后移,a[0] = tmp,数组变为a[10] = {3,10,4,6,5,2,1,9,8,7} ; 第二次tmp值是a[2],因为tmp值小于a[1],所以把a[1]的值往后移,tmp不小于a[0],所以a[0]不用往后移,tmp的值就放在a[1],数组变为a[10] = {3,4,10,6,5,2,1,9,8,7},以此类推,每次设一个tmp值,如果tmp小于前一个数,就把前一个数往后移,如果不大于就放在当前位置。

代码:

<span style="font-size:18px;"><span style="font-size:18px;"><pre name="code" class="cpp">void InsertSort(int *a,int size){int i,j;for(i = 0;i < size-1;++i){int tmp = a[i+1];for(j = i+1;j > 0;--j){if(tmp < a[j-1]){a[j] = a[j-1];}else{a[j] = tmp;break;}}}}</span></span>


它的时间复杂度最好情况是O(n),最坏情况是O(n^2),平均是O(n^2)

希尔排序:

希尔排序是对插入排序的一种优化,假设最小的值或者接近最小的值在数组的最后,就需要移动n次才能把它放在正确的位置。希尔排序设置了一个间距值,每次不是往后移动到下一个位置,而是移动到距离它为间距值的位置。

代码:

<span style="font-size:18px;"><span style="font-size:18px;">void ShellSort(int *a,int size){assert(a);int gap = size;while(gap > 1){gap = gap/3 + 1;for(int i = gap;i < size;++i){int index = i;int tmp = a[index];int end = index - gap;while(end >= 0 && tmp < a[end]){a[end + gap] = a[end];end -= gap;}a[end + gap] = tmp;}}}</span></span>

画图说明:



它的时间复杂度最好情况是O(n),最坏情况是O(n^2),平均是O(n^1.3)


选择排序:

 思路是第一趟找到最小(或是最大)的数的下标,然后将它和a[0](或是a[n-1])交换,第二趟找到次小(或是次大)的数,与a[1](或是a[n-2])交换,但这样效率较低,对它优化的思路是每一趟找到最大和最小的数,但交换的时候需要注意。

代码:

<span style="font-size:18px;"><span style="font-size:18px;">void SelectSort(int *a,int size){int min;int max;int i,j;for(i = 0;i < size-1;++i){min = i;max = i;for(j = i + 1;j < size - i;++j){if(a[j] < a[min])min = j;if(a[j] > a[max])max = j;}if(min != i)swap(a[i],a[min]);if(min != j-1){if(max != i && max != j-1)    swap(a[j-1],a[max]);if(max != j-1 && max == i)    swap(a[j-1],a[min]);}}}</span></span>


它的时间复杂度最好情况是O(n^2),最坏情况是O(n^2),平均是O(n^2)


堆排序:

建一个大堆(这里一定是大堆,而不是小堆,因为小堆只能满足根节点是树里面最小,左右子数的值无法比较)然后

将堆顶的数和a[n-1]交换,再将堆的大小缩小进行调整,下一次堆顶的数就是次大的,将它和a[n-2]交换,直到全部排完。

代码:

<span style="font-size:18px;">void AdjustDown(int *a,int size,int root){int child = root*2 + 1;while(child < size){if(child + 1 < size && a[child + 1] > a[child]){++child;}if(a[child] > a[root]){swap(a[child],a[root]);root = child;child = root * 2 + 1;}else{break;}}}void HeatSort(int *a,int size)   //升序{for(int i = (size - 2)/2;i >= 0;i--)  //建一个大堆{AdjustDown(a,size,i);}for(int i = 0;i < size-1;i++){swap(a[0],a[size-1-i]);AdjustDown(a,size-1-i,0);}}</span>

它的时间复杂度最好情况是O(n*lgn),最坏情况是O(n*lgn),平均是O(n*lgn)


快速排序:

它使用的方法是分治法,划分成子问题,第一次选一个数,进行一趟排序后,这个数左边的数都比它小,右边的数都比它大,再对这个数左边和右边分别排序。
它最坏的情况是每次选的基数都是最大或是最小值,所以可以对它进行优化,选择基数的时候不是选择 最左或是最右的数而是选择最左,最右和中间的数当中值处于中间的数。
因为快速排序要一直递归直到只有一个值,当区间比较小时它的效率会较低,所以对它的第二个优化是当区间较小时就用插入排序。

<span style="font-size:18px;"><span style="font-size:18px;">int GetMidIndex(int left,int mid,int right){if(left < right){if(mid < left)return left;else if(mid > right)    return right;elsereturn mid;}else{if(mid < right)return right;else if(mid > left)return left;else return mid;}}int PartionSort(int *a,int left,int right){  int index = GetMidIndex(left,(right-left)/2,right);swap(a[index],a[right]);int begin = left;int end = right - 1;int key = a[right];while(begin < end){while(begin < end && a[begin] <= key)++begin;while(begin < end && a[end] >= key)--end;if(begin < end)swap(a[begin],a[end]);}if(a[begin] > key){swap(a[begin],a[right]);return begin;}else{return right;}}void QuickSort(int *a,int left,int right){assert(a);if(left - right > 13){int boundary = PartionSort(a,left,right);QuickSort(a,left,boundary-1);QuickSort(a,boundary+1,right);}else{InsertSort(a,right-left+1);}}</span></span>



归并排序:

思路类似于合并两个单链表,以空间换时间。

<span style="font-size:18px;">void MergeSection(int *a,int *tmp,int begin1,int end1,int begin2,int end2){int index = begin1;while(begin1 <= end1 && begin2 <= end2){if(a[begin1] < a[begin2])tmp[index++] = a[begin1++];elsetmp[index++] = a[begin2++];}while(begin1 <= end1)tmp[index++] = a[begin1++];while(begin2 <= end2)tmp[index++] = a[begin2++];}void _MergeSort(int *a1,int *tmp,int left,int right){assert(a);if(left < right){int mid = (right+left)/2;_MergeSort(a,tmp,left,mid);_MergeSort(a,tmp,mid+1,right);MergeSection(a,tmp,left,mid,mid+1,right);memcpy(a+left,tmp+left,(right-left+1)*4);}}void MergeSort(int *a1,int size){int *tmp = new int[size];_MergeSort(a,tmp,0,size-1);delete[] tmp;}</span>


计数排序:

<span style="font-size:18px;">void CountSort(int *a,size_t size){int max = a[0];int min = a[0];for(int i = 1;i < size;++i){if(a[i] > max)max = a[i];else if(a[i] < min)min = a[i];}int range = max-min+1;int *CountArray = new int[range];memset(CountArray,0,sizeof(int)*size);for(int i = 0;i < size;++i){CountArray[a[i] - min]++;}int index = 0;for(int i = 0;i < range;++i){while(CountArray[i]-- > 0){a[index++] = i+min;}}}</span>

基数排序:

<span style="font-size:18px;">int GetMaxBit(int *a,size_t size){int digit = 1;int max = 1;for(int i = 0;i < size;++i){while(a[i] >= max){++digit;max *= 10;}}return digit;}void DigitSortLSD(int *a,size_t size){assert(a);int MaxBit = GetMaxBit(a,size);int *bucket = new int[size];int count[10];int start[10];int digit = 1;int bit = 1;while(bit <= MaxBit){memset(count,0,sizeof(int)*10);memset(start,0,sizeof(int)*10);for(int i = 0;i < size;++i){int num = a[i]/digit %10;count[num]++;}start[0] = 0;for(int i = 1;i < size;++i){start[i] = start[i-1] + count[i-1];}for(int i = 0;i < size;++i){int num = a[i]/digit %10;bucket[start[num]++] = a[i];}memcpy(a,bucket,sizeof(int)*10);digit *= 10;++bit;}}</span>







0 0
原创粉丝点击