插入排序
选择排序
快速排序
堆排序
希尔排序
归并排序
稳定性
时间、空间复杂度
一、插入排序(insertion sort)
实际运行时间,更多地取决于输入序列所含逆序对的总数
template <typename T> void List <T>:: insertionSort( Posi(T) p, int n){
for(int r=0;r<n;r++){
insertAfter(search(p->data,r,p),p->data);//查找+插入
p=p->succ; remove(p->pred);
}
}
性能分析:O(n)
二、选择排序(selection sort)
template <typename T> void List <T> ::selectionSort(Posi(T) p, int n){
Posi(T) head =p->pred; Posi(T) tail =p; //待排序区间(head,tail)
for(int i=0; i<n; i++) tail=tail->succ; //head/tail可能是头/尾哨兵
while(1<n){
//反复从(非平凡的)待排序区间找出最大者,并移至有序区间前段
insertBefore(tail, remove(selectMax(head->succ,n)));
tail=tail->red; n- -;//待排序区间、有序区间的范围,均同步更新
}
}
当selectMax()复杂度为theta(n)时 ,总体复杂度为theta(n^2) ,尽管如此,元素移动操作远远少于bubble sort,复杂度主要来自于比较操作 ,但是我们可以将selectMax()的复杂度降低为theta(log n)
三、快速排序(Quicksort)
快速排序是一种常用的算法,它利用了分治策略(Divide and Conquer)。虽然它在最坏的情况下可能达到O(n^2)的时间复杂度,但是在平均的情况下,它一般都是非常有效的,所以是一种实用的算法。
算法思路:
选出一个轴点P,令P的左侧元素均小于P点的元素,右侧均大于P点的元素
伪代码:
quickSort(arr[],lo,hi){
if(lo<hi){
p=partition(arr,lo,hi);
quickSort(arr,lo,pi-1);
quickSort(arr,pi+1,hi);
}
}
最坏情况下时间复杂度:O(n^2)
最好情况下时间复杂度:O(n*lg n)
四、堆排序(heap sort)
算法思路:
建堆过程即为排序过程。
堆通常以数组形式表现
Representation | Explanation |
---|---|
Arr[(2*i)+1] | Returns the left child node |
Arr[(2*i)+2] | Returns the right child node |
Arr[(i-1)/2] | Returns the parent node |
class Heap{
public:
inline int left(int idx){
return (idx<<1)+1;
}
inline int right(int idx){
return (idx<<1)+2;
}
void max_heapify(vector<int>& nums, int idx){
int largest =idx;
int l =left(idx), r =right(idx);
if(l<heap_size && nums[l]>nums[largest]) largest=l;
if(l<heap_size && nums[r]>nums[largest]) largest=r;
if(largest!=idx) {
swap(nums[idx],nums[largest]);
max_heapify(nums,largest);
}
}
void build_max_heap(vector<int> & nums){
heap_size=nums.size();
for(int i=(heap_size>>1)-1;i>=0;i--)
max_heapify(nums,i);
}
private:
int heap_size;
}
排序时间复杂度为O(n*lg n)
五、希尔排序(shell sort)
将整个序列看作一个矩阵,逐列w-sorting
递减增量 diminishing increment
由粗到细:重排矩阵,使其更窄,再次逐列排序w-ordered
逐步求精:如此往复,直至矩阵变成一列1-sorting
步长序列 step sequence:由各矩阵宽度构成的逆序列
优劣
1.不需要大量的辅助空间,和归并排序一样容易实现
2.希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n^2),而Hibbard增量的希尔排序的时间复杂度为O(n^(3/2)),希尔排序时间复杂度的下界是n*log2n
3.希尔排序没有快速排序算法快,因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择
希尔算法在最坏情况下和平均情况下执行效率相差不是很多,而快速排序在最坏情况下的执行效率会非常差。
void shellsort(int v[],int n)
{
int gap,i,j,temp;
for (gap = n/2; gap > 0; gap /= 2)
{
for(i = gap; i < n; i++)
for(j = i-gap; j>=0 && v[j]>v[j+gap]; j -= gap)
{
temp = v[j];
v[j] = v[j+gap];
v[j+gap] = temp;
}
}
}
六、归并排序(merge sort)
归并排序(merge sort)
归并排序利用了分治(divide-and-conquer)的思想。
算法思路如下:
MergeSort(arr[],l,r)
If(r>l):
1. 找到中点,将数组一分为二:mi=(l+r)/2
2. 对第一个部分进行归并排序:mergeSort(arr,l,m)
3. 对第二部分进行归并排序:mergeSort(arr,m+1,r)
4. 将上面两个排好序的序列融合:merge(arr,l,m,r)
性能分析:
1.是稳定的排序算法