排序算法

    技术2022-05-20  49

    计数排序

    计数排序, 基数排序, 桶排序等非比较排序算法,平均时间复杂度都是O(n). 这些排序因为其待排序元素本身就含有了定位特征,因而不需要比较就可以确定其前后位置,从而可以突破比较排序算法时间复杂度O(nlgn)的理论下限.

    计数排序是最简单的特例,它要求待排序元素是位于0到k之间的正整数, 因而它是很特殊的情况,基本上没有特别的应用价值; 但是另一方面, 它又是基数排序的基础,或者说是一部分,所以简单的描述一下:

    输入数组 A : 元素特征是 0-k的正整数,可以有重复值;

    输出数组 B : 输出A的一个非减序列

    中间数组 C : 大小是k, 它的i( 0<= i <= k)索引位置存储的是A元素集合中值是k的元素的个数有关.

     

    算法的基本思想是:

    统计A中元素的值的集合, 以A中元素的值为索引, 将值的个数填写到中间数组C的对应处. 对C从头开始自累加, 这样C中存储的就是, 当输入数组A中的值为当前索引时, 它前面的元素数量(包含重复元素). 将C依次输出到输出数组中.

     

     

    基数排序:

     

    稳定排序的意思是指, 待排序相同元素之间的相对前后关系,在各次排序中不会改变.

    比如实例中具有十位数字5的两个数字58和356, 在十位排序之前356在58之前,在十位排序之后, 356依然在58之前.

    稳定排序能保证,上一次的排序成果被保留,十位数的排序过程能保留个位数的排序成果,百位数的排序过程能保留十位数的排序成果.

    基数排序是非比较排序算法,算法的时间复杂度是O(n). 相比于快速排序的O(nlgn),从表面上看具有不小的优势.但事实上可能有些出入,因为基数排序的n可能具有比较大的系数K.因此在具体的应用中,应首先对这个排序函数的效率进行评估.

     

    举例如下:

    准备10个vector<int>, 从最低位数字开始,放入相应的桶里, 然后再顺序取出来,然后再从次低位放入相应桶里,在顺序取出来. 比如:N=5,分别是:4,10,7,123,330 :101 2 3 :123,334 :45 6 7 :78 9

    顺次取出来:10,123,33,,4,70 :4,71 :102 :1233 :334 5 6 7 8 9

    依次取出来:4,7,10,123,330 :4,7,10,331 :1232 3 4 5 6 7 8 9

    依次取出来:4,7,10,33,123

    代码如下:

    #include <iostream> #include <string> #include <queue> #include <vector> using namespace std; size_t n; //n个数 size_t maxLen=0; //最大的数字位数 vector< queue<string> > vec(10); //10个桶,用string存数据有一个好处就是每一位很容易得到  vector<string> result; void RadixSort() { for(size_t i=0;i<maxLen;++i) { for(size_t j=0;j<result.size();++j) { if( i>=result[j].length() ) { vec[0].push(result[j]); } else { vec[ result[j][result[j].length()-1-i]-'0' ].push(result[j]); } } result.clear(); for(size_t k=0;k<vec.size();++k) { while(!vec[k].empty()) { result.push_back(vec[k].front()); vec[k].pop(); } } } } int main() { cin>>n; string input; for(size_t i=0;i<n;++i) { cin>>input; result.push_back(input); if(maxLen == 0 || input.length()>maxLen) { maxLen=input.length(); } } RadixSort(); for(size_t i=0;i<n;++i) { cout<<result[i]<<" "; } cout<<endl; return 0; }

     

     

    快速排序,堆排序,归并排序:

    int partition(int arr[],int s,int e) { int tmp = arr[s]; int low = s; int high = e; while(low < high) { while(low < high && arr[high]>= tmp) high--; arr[low] = arr[high]; while(low < high&& arr[low] <= tmp) low++; arr[high] = arr[low]; } arr[low] = tmp; return low; } int QuickSort(int arr[],int s,int e) { if(s > e) return -1; if( s == e) return 0; int p = partition(arr,s,e); QuickSort(arr,s,p-1); QuickSort(arr,p+1,e); return 0; } //数组从0开始,则 k 的孩子结点为 2*k+1,2*k+2, int AdjustHeap(int arr[],int k,int len) { //可以取到arr[len]这个元素 //最大堆 int p = k; //根结点这p,孩子结点为q int q; if( p > len ) return -1; while( p <= len) { q = 2*p + 1 ;//孩子结点 if(q > len ) break; if(q+1 <= len && arr[q+1] > arr[q]) //右子结点比左子结点小 q++; if(arr[q] > arr[p]) { swap(arr[q],arr[p]); p = q; } else break; } return 0; } int HeapSort(int arr[],int len) { for(int i=len/2 ; i>=0; i--)//建堆 AdjustHeap( arr,i,len); for(int i=len; i>0; i--)//排序 { swap(arr[0],arr[i]); AdjustHeap(arr,0,i-1); } return 0; } int Merge(int arr[],int s,int mid,int e) { int* tmp = new int[e-s+1]; int i = s, j = mid+1, k = 0; while(i <= mid && j <= e) { if(arr[i] <= arr[j] ) tmp[k++] = arr[i++]; else tmp[k++] = arr[j++]; } while(i <= mid) tmp[k++] = arr[i++]; while(j <= e) tmp[k++] = arr[j++]; memcpy(arr+s,tmp,(e-s+1)*sizeof(int));//注意此处大小一定要乘以sizeof delete tmp; return 0; } int MergeSort(int arr[],int s,int e) { if(s > e) return -1; if( s==e ) return 0; int mid = s+ (e-s)/2; MergeSort(arr,s,mid); MergeSort(arr,mid+1,e); Merge(arr,s,mid,e); return 0; } int main() { int arr[] ={0,2,6,8,3,5,7,9,1,3,4}; int len = sizeof(arr)/sizeof(arr[0]); // QuickSort(arr,0,len-1); //HeapSort(arr,len-1); MergeSort(arr,0,len-1); for(int i=0;i<len;i++) { cout<<arr[i]<<" "; } cout<<endl; system("pause"); return 0; }

     

    二分插入排序应用:

     

     /* 请把一个整形数组中重复的数字去掉。例如: 1, 2, 0, 2, -1, 999, 3, 999, 88 答案应该是: 1, 2, 0, -1, 999, 3, 88 */ #include <iostream> using namespace std; int cnt = 0; //最后数组中不重复的元素的最后下标... int BiSearch(int arr[],int s,int e,int v) { //序列为升序,查找 arr[i] > v , i最小 ,找不到返回-1  if( s > e ) return -1; while(s < e - 1) { int mid = s+(e-s)/2; if(v >= arr[mid] ) s = mid ; else e = mid; } if(arr[s] > v) return s; else if(arr[e] > v) return e; else return -1; } int BiInsertSort(int arr[],int len) { for( int k=1;k <=len; k++ ) { //查找 arr[i] > arr[k] 的最小i int pos = BiSearch(arr,0,cnt,arr[k]); if(pos == -1) //没找到 说明arr[k]比前面cnt个元素都 >= { if(arr[k] != arr[cnt]) arr[++cnt] = arr[k]; } else if( pos==0 || arr[pos] != arr[pos-1]) //如果没有重复元素 { int tmp =arr[k] ;//先把该值记录下来,不然可能被覆盖了 for(int t=cnt; t>=pos; t--)//移位 arr[t+1] = arr[t]; arr[pos] = tmp ;//插入 ++cnt; } } return 0; } int main() { int arr[] = {1,2,0,2,-1,999,3,999,88}; int len = sizeof(arr)/sizeof(arr[0]); BiInsertSort(arr,len-1); for(int i=0; i<=cnt; i++) cout<<arr[i]<<" "; cout<<endl; system("pause"); return 0; }


    最新回复(0)