排序总结
1.冒泡排序
时间复杂度:n^2,空间复杂度:O(1),稳定。冒泡这个名字十分形象,排序过程中通过将相邻两个元素进行调换,达成把最大值(或最小值)换到末尾
for (int i = 0;i < n - 1;i ++){
for (int j = 0;j < n - 1 - i;j ++){
if (a[j] > a[j + 1]){
swap(a[j],a[j + 1]);
}
}
}
2.快排(真的是太快辣)
时间复杂度:nlogn,空间复杂度:log n,不稳定。俗称交换排序。
void QuickSort(T *q, const int left, const int right) { if(left<right) { int i=left, j=right; int temp = q[left]; while(i<j) { while(q[j]>=temp && i<j) { j--; } while(q[i]<=temp && i<j) { i++; } swap(q[i],q[j]); } swap(q[left], q[j]); QuickSort(q, left, j-1); QuickSort(q, j+1, right); } }
3.插入排序
时间复杂度:n^2,空间复杂度:o(1),稳定。把每一个插到正确位置上。
void insertArray(short * pArray, short count) {
short temp;
short pos;
for (int i = 1; i < count; i ++) {
temp = pArray[i];
pos = i - 1;
while (temp < pArray[pos]) {
pArray[pos + 1] = pArray[pos];
pos--;
}
pArray[pos + 1] = temp;
}
}
4.希尔排序
时间复杂度:nlogn,空间复杂度:O(1),不稳定主要思想是: 先将整个记录, 通过间隔分成若干个子序列, 分别进行插入排序, 待整个序列基本有序时, 再进行一次插入排序.
void shell_sort(int parr[], int len) { int j; int tempval; int jump = len >> 1; //jump为数组长度一半的大小 while (jump != 0) //循环插入 { for (int i = jump; i < len; ++i) { tempval = parr[i]; j = i - jump; while (j >= 0 && tempval < parr[j]) { parr[j + jump] = parr[j]; j = j - jump; } parr[j + jump] = tempval; } jump >>= 1; //jump除等于2 } }
5.选择排序
时间复杂度:n^2,空间复杂度:O(1),不稳定。在队列中找到最小元素放到已排序列最后。
void selectArray(short * pArray, short count) {
short temp; //存储每次选择元素的数值
short k; //存储所选择元素的小标
for (short i = 0; i < count; i ++) {
temp = pArray[i];
k = i;
for (short j = i; j < count; j ++) {
if (temp > pArray[j]) {
temp = pArray[j];
k = j;
}
}
pArray[k] = pArray[i];
pArray[i] = temp;
}
}
6.堆排序
时间复杂度nlogn 空间复杂度O(1),不稳定
void HeapSort(int a[],int length) { int temp; BuildMaxHeap(a,length); for (int i = length - 1; i >= 1; i--) { //交换根节点和数组的最后一个节点 temp = a[i]; a[i] = a[0]; a[0] = temp; MaxHeapify(a, 0, 0, i-1);//维护从下标为i-1到0的子数组 } }
7.归并排序
时间复杂度nlogn,空间复杂度 O n+logn,稳定
public static void mergeAB(int [] arrA,int [] arrB,int [] arrC){ //循环遍历两个需要归并的数组 for(int a=0,b=0,c=0;c<(arrA.length+arrB.length);){ //判断两个数组是否对应遍历完成 if(a==arrA.length){ //遍历完成A数组,则对应B中的元素只需要直接复制到C数组中 arrC[c++] = arrB[b++]; continue; } if(b==arrB.length){ arrC[c++] = arrA[a++]; continue; } //如果两个数组都没有遍历完,则进行比较操作 arrC[c++] = arrA[a]<arrB[b]?arrA[a++]:arrB[b++];
}
}
8.计数排序
时间复杂度 kn,空间复杂度 n+k,稳定计数排序是一种非比较排序算法,它用于排序的数的范围较小,例如在0到100之间。计数排序的基本思想是,统计数组中每个元素出现的次数,然后根据出现次数将元素排序。
void countingSort(int arr[], int n) { int maxVal = arr[0]; for (int i = 1; i < n; i++) { if (arr[i] > maxVal) { maxVal = arr[i]; } } int count[maxVal+1], output[n]; memset(count, 0, sizeof(count)); for (int i = 0; i < n; i++) { count[arr[i]]++; } for (int i = 1; i <= maxVal; i++) { count[i] += count[i-1]; } for (int i = n-1; i >= 0; i--) { output[count[arr[i]]-1] = arr[i]; count[arr[i]]--; } for (int i = 0; i < n; i++) { arr[i] = output[i]; } }
9.桶排序
时间复杂度 n+k,空间复杂度 O(k),稳定桶排序将输入数据的区间均匀分成若干份,每一份称作“桶”。分别对每一个桶的内容进行排序,再按桶的顺序输出则完成排序。
void Insert(vector & bkt, double num) { for (vector::iterator p = bkt.begin(); p != bkt.end(); ++p) if (*p > num) { bkt.insert(p, num); return ; } bkt.push_back(num); //没有找到,就放最后 }
void BucketSort(double * const begin, double * const end) { //假设输入数据都是小数[0,1) int n = end - begin; int i; vector<vector*> bucket(n); //为什么是n个桶,应该和hash一个原理
for (i = 0; i < n; ++i)
bucket[i] = new vector<double>;
for (i = 0; i < n; ++i) { //按顺序插入到桶中
Insert(*bucket[static_cast<int>(*(begin + i) * n)], *(begin + i));
}
int j = 0, k = 0;
for (i = 0; i < n; ++i) {
while (k >= bucket[j]->size()) { //如果出现连续的空桶
++j;
k = 0;
}
*(begin + i) = (*bucket[j])[k++];
}
for (i = 0; i < n; ++i)
delete bucket[i];
}
10.基数排序
时间复杂度 n+k,空间复杂度O(n+k),稳定基数排序是一种思想很值得学习的排序方法。
它突破了正常的排序思维:先排高位,如果高位相同再排次高位,直至最低。它的思想是利用稳定排序从低位开始排,最后再排最高位。
另外它用来划分的位不一定是一位一位的划分,还可以是每几位一组,然后按组从低到高来排序。
事实上,当总位数b等于O(lgn),并且每一组的位数r等于logn时,基数排序的时间复杂度为θ(n)。
int PickDigitOn_i(int n, const int i) { for (int k = 1; k <= i; ++k) n /= 10; return n % 10; }
void stablesort_onDigit_i(int * const begin, int * const end, int d) { //使用计数排序作为稳定排序 int temp[10] = {0}; //十进制数 vector out(end - begin);
for (int i = 0; i < end - begin; ++i)
++temp[PickDigitOn_i(*(begin + i), d)];
for (int i = 1; i < 10; ++i)
temp[i] += temp[i-1];
for (int i = end - begin - 1; i >= 0; --i) {
out[temp[PickDigitOn_i(*(begin + i), d)] - 1] = *(begin + i);
--temp[PickDigitOn_i(*(begin + i), d)];
}
for (int i = 0; i < end - begin; ++i)
*(begin + i) = out[i];
}
void RadixSort(int * const begin, int * const end) { //假设三位数的排序 for (int i = 0; i < 3; ++i) { stablesort_onDigit_i(begin, end, i); } }