十大经典排序算法
Posted 风起时~微凉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了十大经典排序算法相关的知识,希望对你有一定的参考价值。
稳定排序:
冒泡排序、插入排序、归并排序
非稳定排序:
选择排序、希尔排序、堆排序、快速排序
1、冒泡排序
冒泡排序就是把小的元素往前调或者把大的元素往后调,比较是相邻的两个元素比较,交换也发生在这两个元素之间。(类似于气泡上浮过程)
动图如下:
步骤:
1、比较相邻的元素,如果第一个比第二个大,则交换
2、对每对相邻元素重复步骤1操作,筛选出最大元素
3、针对所有元素重复步骤1、2(除最后一个元素,已经是最大)
示例代码:
void bubbleSort(std::vector<int> &vecArry)
{
for (int i = 0;i < vecArry.size();i++)
{
for (int j = 0;j < vecArry.size() - i -1;j++)
{
if (vecArry[j] > vecArry[j+1])
{
int nTemp = vecArry[j];
vecArry[j] = vecArry[j+1];
vecArry[j+1] = nTemp;
}
}
}
}
//优化代码
void bubbleSort(std::vector<int> &vecArry)
{
bool bSwitch = false;
for (int i = 0;i < vecArry.size();i++)
{
for (int j = 0;j < vecArry.size() - i -1;j++)
{
if (vecArry[j] > vecArry[j+1])
{
bSwitch = true;
int nTemp = vecArry[j];
vecArry[j] = vecArry[j+1];
vecArry[j+1] = nTemp;
}
}
if (!bSwitch)
{
return;
}
}
}
2、选择排序
从未排序序列中找到最小(最大),放在已排序序列尾部
动图如下:
步骤:
1、找到排序队列最小(最大)元素,存放在序列起始位置
2、在未排序序列找到最小(最大)元素,放在已排序序列尾部
3、重复1、2步骤
示例代码:
void selectSort(std::vector<int> &vecArry)
{
for(int i = 0; i < vecArry.size(); ++i)
{
int nIndex = i;
for (int j = i+1; j < vecArry.size();++j)
{
if (vecArry[j] < vecArry[nIndex])
{
nIndex = j;
}
}
int nTemp = vecArry[i];
vecArry[i] = vecArry[nIndex];
vecArry[nIndex] = nTemp;
}
}
3、插入排序
用未排序序列第一个元素,从已排序序列尾部到起始位置方向开始比较,也就是插入元素和已排序最大元素开始比较,一直找到比它小的元素位置后插入。
动图如下:
步骤:
1、设置第一个元素为已排序
2、取出下一个元素,在已排序序列尾部向前比较
3、如果该元素(已排序)大于新元素(需插入元素),将该元素移到下一位置
4、重复步骤3,找到已排序元素小于或等于新元素
5、将新元素插入已排序序列
6、重复2~5
示例代码:
void insertSort(std::vector<int> &vecArry)
{
for (auto i = 1; i < vecArry.size(); ++i)
{
int m = vecArry[i];
for (int n = i-1; n >=0; --n)
{
if (m < vecArry[n])
{
int nTemp = vecArry[n + 1];
vecArry[n+1] = vecArry[n];
vecArry[n] = nTemp;
}
}
}
}
4、快速排序
以一个元素为基数,将小于基数的元素移到基数前面,大于基数的元素移到基数后面,对左右区间递归以上步骤,知道区间只有一个数
动图如下:
步骤:
1、选取一个数为基数
2、将比基数小的元素移到基数前面
3、将比基数大的元素移到基数后面
4、对基数左右区间重复1~3步骤,直到区间只有一个数
示例代码:
void quickSort(std::vector<int> &vecArry,int nLeft,int nRight)
{
if (nLeft >= nRight)
{
return;
}
int nLow = nLeft;
int nHight = nRight;
int nBase = vecArry[nLeft];
while (nLow < nHight)
{
while( nLow < nHight && nBase< vecArry[nHight])
{
nHight--;
}
if (nLow < nHight)
{
vecArry[nLow++] = vecArry[nHight];
}
while (nLow < nHight && nBase > vecArry[nLow])
{
nLow++;
}
if (nLow < nHight)
{
vecArry[nHight--] = vecArry[nLow];
}
}
vecArry[nLow++] = nBase;
quickSort(vecArry,nLeft,nLow-1);
quickSort(vecArry,nHight+1,nRight);
}
5、希尔排序
希尔排序可以理解成插入排序的优化版本。希尔排序是先将任意间隔为N的元素有序,刚开始可以是N=n/2,接着让N=N/2,让N一直缩小,当N=1,时,此时序列间隔为1有序。
动图如下:
步骤:
1、初始间隔N=数组长度/2
2、对间隔为N的分组进行插入排序,直至有序
3、缩小N值,N=N/2;
4、重复2、3步骤,直至间隔N=1
示例代码:
void shellSortCore(std::vector<int> &vecArry)
{
int gap = vecArry.size()/2;
while(gap)
{
for (int i = gap; i < vecArry.size(); i++)//分了多少个组
{
int m = vecArry[i];
for (int n = i - gap; n >=0; --n)
{
if (m < vecArry[n])
{
int nTemp = vecArry[n + gap];
vecArry[n+gap] = vecArry[n];
vecArry[n] = nTemp;
}
}
}
gap/=2;
}
}
6、堆排序
堆可以分为大根堆和小根堆,而堆排序是根据堆的数据结构设计的一种排序。
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
动图如下:
步骤:
1、将待排序序列构建成大根堆,此堆为初始无序堆
2、将堆顶元素和最后一个元素交换,此时得到新的N-1无序堆和有序序列
3、重复2直到无序堆为1,此时有序序列为N-1
示例代码:
int nLen = 0;
void swap(std::vector<int> &vecArry,int nSrc, int nDes)
{
int nTemp = vecArry[nSrc];
vecArry[nSrc] = vecArry[nDes];
vecArry[nDes] = nTemp;
}
void funcBuild(std::vector<int> &vecArry, int n)
{
int left = 2 * n + 1;
int right = 2 * n + 2;
int largest = n;
if (left < nLen && vecArry[left] < vecArry[largest]) {
largest = left;
}
if (right < nLen && vecArry[right] < vecArry[largest]) {
largest = right;
}
if (largest != n) {
swap(vecArry, n, largest);
funcBuild(vecArry, largest);
}
}
void heapify_sort(std::vector<int> &vecArry)
{
nLen = vecArry.size();
for (int i = nLen/2-1; i >= 0; i--)
{
funcBuild(vecArry,i);
}
for (int j = nLen-1;j >= 0; j--)
{
swap(vecArry,0,j);
nLen--;
funcBuild(vecArry,0);
}
}
7、计数排序
将待排序序列元素出现次数做为键值存在新开辟数组空间中
动图如下:
步骤:
1、找出待排序序列A最大元素Max
2、新开辟一个Max+1的数组B,初始值为0
3、将序列A中元素值做为数组B索引x,A中元素出现次数做数组B索引为x的值
4、开辟一个长度和A序列大小相同的数组C
5、循环取出数组B的值存入C中,取出一个B值--
示例代码:
void countSort(std::vector<int> &vecArry)
{
int nMax = 0;
for (auto &item : vecArry) {
if (nMax < item)
{
nMax = item;
}
}
std::vector<int> vecCount(nMax+1,0);
for (int i = 0; i < vecArry.size();i++)
{
vecCount[vecArry[i]]++;
}
std::vector<int> vecResult(vecArry.size(),0);
int nIndex = 0;
for (int j = 0; j< vecCount.size();j++)
{
while(vecCount.at(j) > 0)
{
vecResult[nIndex++] = j;
vecCount[j]--;
}
}
}
8、归并排序
归并排序采用分治思想,把待排序序列分成N个子序列,子序列排序后,合并两个子序列实现排序
动图如下:
步骤:
1、把长度为N的序列分成N/2个子序列
2、对子序列进行归并排序
3、将有序子序列合并成一个子序列
示例代码:
void merge(std::vector<int> &vecArry,int nLeft, int nMid, int nRight)
{
int nLen = nRight-nLeft+1;
int nTempLeft = nLeft, nTempRight = nMid+1;
int nIndex = 0;
std::vector<int> vecTemp(nLen,0);
while (nTempLeft <= nMid && nTempRight <= nRight)
{
vecTemp[nIndex++] = vecArry[nTempLeft] <= vecArry[nTempRight] ? vecArry[nTempLeft++] : vecArry[nTempRight++];
}
while(nTempLeft <= nMid)
{
vecTemp[nIndex++] = vecArry[nTempLeft++];
}
while (nTempRight <= nRight)
{
vecTemp[nIndex++] = vecArry[nTempRight++];
}
for (int i = 0; i < nLen; i++)
{
vecArry[nLeft+i] = vecTemp[i];
}
}
void mergeSort(std::vector<int> &vecArry, int nLeft, int nRight)
{
if (nLeft == nRight)
{
return;
}
int nMid = (nLeft + nRight)/2;
mergeSort(vecArry,nLeft,nMid);
mergeSort(vecArry,nMid+1,nRight);
merge(vecArry,nLeft,nMid,nRight);
}
9、桶排序
桶排序是将数组分别放到有限数量的桶里。每个桶再进行排序。桶排序是鸽巢排序的一种归纳结果
动图如下:
步骤:
1、设置一定数量的空桶
2、遍历待排序序列,将每个元素放入对应桶里
3、对每个不空的桶进行排序
4、从不空的桶将元素从桶中取出
示例代码:
void bucketSort2(std::vector<int> &vecArry)
{
int nMax = vecArry[0];
for (auto &value : vecArry)
{
if (value > nMax)
{
nMax = value;
}
}
std::vector<int> vecTemp(nMax+1,0);
for (auto &value : vecArry)
{
vecTemp[value]++;
}
int nIndex = 0;
for (int i = 0; i < vecTemp.size(); ++i)
{
while (vecTemp[i] > 0)
{
vecArry[nIndex++] = i;
vecTemp[i]--;
}
}
}
void bucketSort(std::vector<int> &vecArry) {
int nMax = vecArry.at(0);
int nMin = vecArry.at(0);
for (auto &data : vecArry)
{
if (data > nMax)
{
nMax = data;
}
if (data < nMin)
{
nMin = data;
}
}
int nValue = nMax - nMin;//差值
std::vector<std::vector<int>> vecTemp;
int nLen = vecArry.size();//序列长度
vecTemp.resize(nLen);
for (auto &value : vecArry)
{
//nLen-1 个区间
//将差值为nValue平分到nLen-1个区间上
//value-min是当前元素和最小值差值
//nIndex就为(value - nMin)/nValue/(nLen-1)
int nIndex = (value - nMin)/nValue/(nLen-1);
vecTemp[nIndex].push_back(value);
}
for (auto &data : vecTemp)
{
insertSort(data);
}
int nIndex= 0;
for (auto &data : vecTemp)
{
for(auto &value : data)
{
vecArry[nIndex++] = value;
}
}
}
10、基数排序
基数排序是按照低位先排序,然后收集,再按照高位排序,再收集,以此类推,直到最高位。
动图如下:
步骤:
1、取待排序序列中最大数,并获取位数
2、从待排序序列每个元素低位相同放到一个radix数组
3、从多个radix数组取出元素,组成新的待排序序列
4、以此重复2、3(步骤2从低到高位)
示例代码:
void radixSort(std::vector<int> &vecArry) //基数排序
{
int nLen = vecArry.size();
int nMax = vecArry.at(0);
for (auto &value : vecArry)
{
if (nMax < value)
{
nMax = value;
}
}
int nCount = 0;
while(nMax)
{
nMax/=10;
nCount++;
}
int radix = 1;
std::vector<std::vector<int>> vecTemp(10);
for (int i = 0; i < nCount; i++)
{
vecTemp.clear();
vecTemp.resize(10);
for(auto &value : vecArry)
{
int nIndex = (value/radix)%10;
vecTemp.at(nIndex).push_back(value);
}
int nIndex = 0;
for (auto &value : vecTemp)
{
for (auto &data : value)
{
vecArry[nIndex++] = data;
}
}
radix *= 10;
}
}
以上是关于十大经典排序算法的主要内容,如果未能解决你的问题,请参考以下文章