前言
刚开始学的时候,一般都是几大排序一起看,看着看着就晕了,觉得很难。其实没学会的原因只有一个,那就是自己打击了自己的积极性。
如果你心里对它们还存有畏难情绪的话,不妨先看看这些视频,匈牙利民间舞模拟各种排序,很滑稽;) 地址
快速排序
这代码够简洁了吧!
void quickSort(std::vector<int> &a, int left, int right)
{
if(left < right)
{
// 选择左节点为枢纽元
int pivot = a[left];
int low = left, high = right;
// 把数组分成两半,左边的小于pivot,右边的大于pivot
while(low < high)
{
while(high > low && a[high] > pivot)
{
high--;
}
if(low < high)// 1
a[low] = a[high];
while(low < high && a[low] < pivot)
{
low++;
}
if(low < high)// 2
a[high] = a[low];
// 因为你不知道会在哪个while之后结束,所以1,2两处都要加一个判断。
}
// 此时pivot的位置就是正确的了。
a[low] = pivot;
quickSort(a, left, low-1);
quickSort(a, low+1, right);
}
}
归并排序
一句话记忆:”分治与合并“
void merge(std::vector<int> &a, int l, int m, int r)
{
// 用一个辅助数组
std::vector<int> tmp;
int i = l, j = m+1;
// 按序插入到辅助数组中
while(i<=m && j<=r)
{
if(a[i] <= a[j])
tmp.push_back(a[i++]);
else
tmp.push_back(a[j++]);
}
// 拷贝剩下的数据
while(i<=m)
tmp.push_back(a[i++]);
while(j<=r)
tmp.push_back(a[j++]);
// 全部复制到原来的数组
for(int i = 0; i<tmp.size(); i++)
a[l+i] = tmp[i];
}
void mergeSort(std::vector<int> &a, int l, int r)
{
if(l<r)
{
int m = l + (r-l)/2;
mergeSort(a, l, m);
mergeSort(a, m+1, r);
merge(a, l, m, r);
}
}
插入排序
一句话记忆:”不断将新节点插入到一个已经排好序的数组中。“
void insertSort(std::vector<int> &a)
{
for(int i = 1; i<a.size(); i++)
for(int j = i-1; j>=0 && a[j+1]<a[j]; j--)
std::swap(a[j+1],a[j]);
}
希尔排序
一句话记忆:”插入排序的兄弟。“
void shellSort(std::vector<int> &a)
{
int n = a.size();
// 步长每次减半
for(int gap = n/2; gap>0; gap/=2)
// 对应插入排序中 for(int i=1;i<n;i++),gap=1
for(int i = gap; i < n; i++)
// 对应插入排序中 for(int j=i-1;j>=0;j--)
for(int j = i-gap; j>=0 && a[j+gap]<a[j]; j-=gap)
std::swap(a[j+gap], a[j]);
}
堆排序
一句话理解:”把要排序的数组当作一个最大堆,并想办法使其恢复堆序,最后通过将堆顶元素换到末尾实现排序。“
void maxHeapfix(std::vector<int> &a, int heapSize, int index)
{
int iMax = index;
int iLeft = 2*index + 1;// 这里的数组下标从0开始,所以我们要调整一下
int iRight = 2*index + 2;
if(iLeft < heapSize && a[iLeft]>a[iMax])
iMax = iLeft;
if(iRight < heapSize && a[iRight]>a[iMax])
iMax = iRight;
if(iMax != index)
{
std::swap(a[iMax], a[index]);
maxHeapfix(a, heapSize, iMax);
}
}
void heapSort(std::vector<int> &a)
{
int n = a.size();
// 构建最大堆,数组小于3就会直接跳过这里
for(int i = n/2-1; i>=0; i--)
{
maxHeapfix(a, n, i);
}
// 排序
for(int i = n-1; i>0; i--)
{
std::swap(a[0], a[i]);
maxHeapfix(a, i, 0);
}
}
冒泡排序
一句话记忆:”请认真对待每一件事,哪怕它只是个冒泡排序“
void bubbleSort(std::vector<int> &a)
{
for(int i = 0; i<a.size(); i++)
for(int j = 1; j<a.size()-i; j++)
if(a[j] > a[j-1])
std::swap(a[j], a[j-1]);
}
它们的复杂度
稳定性
选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法
参考文章
http://quiz.geeksforgeeks.org/
里面的代码、注释都很精炼很优雅,读起来简直是享受。