排序
十大排序算法


- 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
- 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
冒泡排序:比较相邻的元素。如果第一个比第二个大,就交换它们两个;
for(int i=0;i<n;i++){ for(int j=0;j<n-i-1;j++){ if(a[j]>a[j+1])swap(a[j],a[j+1]); } }
选择排序:每次从未排序的序列中找到最小值,和未排序的第一个交换
for(int i=0;i<n;i++){ int minid=i; for(int j=i+1;j<n;j++){ if(a[j]<a[minid]) minid=j; } swap(a[i],a[minid]); }
快速排序:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
void quick_sort(int a[],int l,int r){ if(l>=r)return ; int i=l-1,j=r+1,x=a[l+r>>1]; while(i<j){ do i++;while(a[i]<x); do j--;while(a[j]>x); if(i<j)swap(a[i],a[j]); } quick_sort(a,l,j); quick_sort(a,j+1,r); }
归并排序:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
- 把长度为n的输入序列分成两个长度为n/2的子序列;
- 对这两个子序列分别采用归并排序;
- 将两个排序好的子序列合并成一个最终的排序序列。
int temp[N]; void merge_sort(int a[],int l,int r){ if(l>=r)return ; int mid=l+r>>1; merge_sort(a,l,mid); merge_sort(a,mid+1,r); int i=l,j=mid+1,k=0; while(i<=mid&&j<=r){ if(a[i]<a[j])temp[k++]=a[i++]; else temp[k++]=a[j++]; } while(i<=mid)temp[k++]=a[i++]; while(j<=r)temp[k++]=a[j++]; for(int i=l,j=0;i<=r;i++,j++)a[i]=temp[j]; }
桶排序:桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。
直接插入排序:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
for(int i=1;i<n;i++){ int current=a[i]; int pre=i-1; while(pre>=0&¤t<a[pre]){ a[pre+1]=a[pre]; pre--; } a[pre+1]=current; }
二分插入排序:把查找部分改为二分查找
表插入排序:表插入排序的基本操作仍是将一个记录插入到已排好序的有序表中。和直接插入排序相比,不同之处仅是修改2n次指针值代替移动记录,排序过程中所需进行的关键字间的比较次数相同。因此表插入排序的时间复杂度仍是O(n2)

表插入排序的结果只是求得一个有序链表,则只能对它进行顺序查找,不能进行随机查找,为了能实现有序表的折半查找,尚需对记录进行重新排列。
重新排列

希尔排序:它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。
void shellSort(int arr[], int n){ int tmp = 0; int step = n / 2; while (step){ for (int i = step; i < n; i++){ tmp = arr[i]; int j = i; while (j >= step && tmp < arr[j - step]){ arr[j] = arr[j - step]; j -= step; } arr[j] = tmp; } step = step / 2; } }
基数排序:基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。
堆排序:堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

void down(int u){ int t = u; if (u * 2 <= cnt && h[u * 2] < h[t]) t = u * 2; if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1; if (u != t){ heap_swap(u, t); down(t); } } void up(int u){ while (u / 2 && h[u] < h[u / 2]){ heap_swap(u, u / 2); u >>= 1; } }
大根堆
#include <iostream> #include <algorithm> using namespace std; const int N = 100010; int n, m; int h[N], cnt; void down(int u) { int t = u; if (u * 2 <= cnt && h[u * 2] > h[t]) t = u * 2; if (u * 2 + 1 <= cnt && h[u * 2 + 1] > h[t]) t = u * 2 + 1; if (u != t) { swap(h[u], h[t]); down(t); } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i ++ ) scanf("%d", &h[i]); cnt = n; for (int i = n / 2; i; i -- ) down(i); for(int i=1;i<=n;i++)cout<<h[i]<<' '; puts(""); return 0; }

浙公网安备 33010602011771号