八大排序
文章目录
冒泡排序(升序)
思想:两两相比,大的往后移,每轮结束数据中最大的数冒到数组最后
优缺点:稳定、不需要辅助空间;但效率低(每次都需要交换数据)
复杂度:(时间换空间,不需要额外空间)
平均时间复杂度:O(n²) 、 最好(已经有序的情况):O(n)、最差(正好倒序的情况):O(n^2)
从前往后冒泡
template<class T>
void PopSort(T * const pdata, size_t size, bool IsUp = true)
{
T swapdata;
for (int i = 0; i < size - 1; ++i)
{
for (int j = 0; j < size - 1 - i; ++j)
{
if (pdata[j] > pdata[j + 1])
{
swapdata = pdata[j];
pdata[j] = pdata[j + 1];
pdata[j + 1] = swapdata;
}
}
}
}
从后往前冒泡
template<class T>
void PopSort(T * const pdata, size_t size, bool IsUp = true)
{
T swapdata;
for (int i = 0; i < size - 1; ++i)
{
for (int j = size - 1; j > i; --j)
{
if (pdata[j] < pdata[j - 1])
{
swapdata = pdata[j];
pdata[j] = pdata[j - 1];
pdata[j - 1] = swapdata;
}
}
}
}
选择排序(升序)
思想:选取一个元素 ,依次比较,选取小于的记录下标,一次循环结束后交换元素
优缺点:相比于冒泡排序,选择的交换次数更少(比较次数没有减少),但是不稳定
复杂度:
时间复杂度:O(n²)
空间复杂度:O(1)
代码实现
template<class T>
void SelectSort(T * const pdata, size_t size, bool IsUp = true)
{
T swapdata;
int limitindex = 0; //极限下标
for (int i = 0; i < size - 1; ++i)
{
limitindex = i;
for (int j = i + 1; j < size; ++j)
{
if (pdata[limitindex] > pdata[j])
{
limitindex = j; //记录交换下标
}
}
swapdata = pdata[limitindex];
pdata[limitindex] = pdata[i];
pdata[i] = swapdata;
}
}
插入排序(升序)
思想:把n个待排序的元素看成为一个有序表和一个无序表。开始时有序表中只包含1个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复
优缺点:快速但是不稳定(比较次数不一定,比较次数越多,插入点后的数据移动越多)但是在链表中插入排序具有绝对优势
复杂度:
时间复杂度度:最好:O(n)最坏:O(n²)
图解
代码实现
template<class T>
void InsertSort(T * const pdata, size_t size, bool IsUp = true)
{
T tempdata;
for (int i = 1; i < size; ++i)
{
tempdata = pdata[i];
int j;
for (j = i - 1; j >= 0; --j)
{
if (tempdata < pdata[j]) //后面小
{
pdata[j + 1] = pdata[j];
}
else
{
break;
}
}
pdata[j + 1] = tempdata;
}
}
归并排序(升序)
思想:将原序列不断进行二分,直至只有一个元素,得到n个只含有一个元素的序列,再将这n个需序列不断地两两合并,最终得到一个有序的序列。
优缺点:效率高,稳定,但需要O(n)的空间复杂度(略高)
复杂度:
时间复杂度:O(nlogn)
代码实现(使用递归方式)
#ifndef SAFE_DELARR
#define SAFE_DELARR(p){if(p!=nullptr){delete []p;p=nullptr;}}
#endif
template<class T>
void MergeSort(T * const pdata, size_t size, bool IsUp = true)
{
if (size > 1)
{
//分割至每个序列只有一个元素
size_t asize = size / 2;
size_t bsize = size - asize;
T * pAbuffer = new T[asize];
T * pBbuffer = new T[bsize];
memcpy(pAbuffer, pdata, sizeof(T)*asize);
memcpy(pAbuffer, pdata + asize , sizeof(T)*bsize);
MergeSort(pAbuffer, asize, IsUp); //递归
MergeSort(pBbuffer, bsize, IsUp);
size_t aindex = 0, bindex = 0, dataindex = 0;
if (IsUp)
{
//向上归并
while ((aindex < asize) && (bindex < bsize))
{
if (pAbuffer[aindex] < pBbuffer[bindex])
{
pdata[dataindex] = pAbuffer[aindex];
++aindex;
}
else
{
pdata[dataindex] = pBbuffer[bindex];
++bindex;
}
++dataindex;
}
}
while (aindex < asize)
{
pdata[dataindex] = pAbuffer[aindex];
++aindex;
++dataindex;
}
while (bindex < bsize)
{
pdata[dataindex] = pBbuffer[bindex];
++bindex;
++dataindex;
}
SAFE_DELARR(pBbuffer);
SAFE_DELARR(pAbuffer);
}
}
使用非递归方式
template<class T>
void MergeSort2(T * const pdata, size_t size, bool IsUp = true)
{
size_t blocksize = 2;
size_t smallblocksize = blocksize / 2;
T * ptempdata = new T[size];
if (IsUp)
{
while (blocksize < 2 * size)
{
memcpy(ptempdata, pdata, sizeof(T)*size);
for (size_t blockheadindex = 0; blockheadindex < size; blockheadindex += blocksize)
{
size_t aindex = blockheadindex;
size_t bindex = blockheadindex + smallblocksize;
size_t dataindex = blockheadindex;
while ((aindex < (blockheadindex + smallblocksize)) && (aindex < size) &&
(bindex < (blockheadindex + blocksize)) && (bindex < size))
{
if (ptempdata[aindex] < ptempdata[bindex])
{
pdata[dataindex] = ptempdata[aindex];
++aindex;
}
else
{
pdata[dataindex] = ptempdata[bindex];
++bindex;
}
++dataindex;
}
while (aindex < (blockheadindex + smallblocksize) && (aindex < size))
{
pdata[dataindex] = ptempdata[aindex];
++aindex;
++dataindex;
}
while ((bindex < (blockheadindex + blocksize)) && (bindex < size))
{
pdata[dataindex] = ptempdata[bindex];
++bindex;
++dataindex;
}
}
smallblocksize = blocksize;
blocksize *= 2;
}
}
if (ptempdata != nullptr)
{
delete[]ptempdata;
ptempdata = nullptr;
}
}
基数排序【桶排序】(升序)
思想:基数排序是根据数位来进行排序的,从个位开始,按照每一位的数进行比较排序
优缺点:稳定,效率极高;但使用范围受限(只适用整数)
复杂度:
时间复杂度:O(n*k)
空间复杂度:O(n+k)
图解
代码实现
template<class T>
void RadixSort(T * const pdata, size_t size, bool IsUp = true, size_t radixtime = 5)
{
T *pBuffer[10] = { nullptr };
int BufferDataNum[10] = { 0 };
for (int i = 0; i < 10; ++i)
{
pBuffer[i] = new T[size]; //存在所有元素都在一个桶内的情况
}
size_t bufferindex = 0; //第几个桶
size_t numbase = 1;
for (size_t rt = 0; rt < radixtime; ++rt)
{
for (int i = 0; i < 10; ++i)
{
BufferDataNum[i] = 0;
}
for (size_t s = 0; s < size; ++s)
{
bufferindex = pdata[s] / numbase % 10;
pBuffer[bufferindex][BufferDataNum[bufferindex]] = pdata[s];
++BufferDataNum[bufferindex];
}
//倒回去
int dataindex = 0;
if (IsUp)
{
for (int bindex = 0; bindex < 10; ++bindex)
{
for (int bn = 0; bn < BufferDataNum[bindex]; ++bn)
{
pdata[dataindex++] = pBuffer[bindex][bn];
}
}
}
numbase *= 10;
}
for (int i = 0; i < 10; ++i)
{
SAFE_DELARR(pBuffer[i]);
}
}
希尔排序(升序)
思想:希尔排序是把数据序列按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的数据个数越来越多,当增量减至1时,整个文件恰被分成一组,整个数据序列就已经排序好了,算法便终止。(内部是插入排序)
优缺点:数据移动量少,效率高;但不稳定。
复杂度:
时间复杂度:O(n^1.5)
图解
代码实现
template<class T>
void ShellSort(T * const pdata, size_t size, bool IsUp = true)
{
size_t step = size / 2; //确定步长
T temp;
if (IsUp)
{
while (step > 0)
{
for (size_t listheadindex = 0; listheadindex < step; ++listheadindex)
{
//内部就是插入排序
for (size_t i = listheadindex + step; i < size; i += step)
{
temp = pdata[i];
int j;
for (j = i - step; j >= 0; j -= step)
{
if (temp < pdata[j])
{
pdata[j + step] = pdata[j];
}
else
{
break;
}
pdata[j + step] = temp;
}
}
step /= 2; //缩减步长
}
}
}
}
快速排序(升序)
思想:
1.选定first和last,并取first或last位置值为key(这里取first位置值为key);
2.从last位置开始,一个个向前(向first位置)取值和key值比较,如果大于等于key值,last位置数据不变,last前移.如果小于 key值的话.将last位置的数据赋值给first位置,结束当次last搜索;
3.从first位置开始,一个个向后(向last位置)取值和key值比较.如果小于等于key值,first位置的数据不变,fisrt后移.如果大于key值的话,将first位置的数据赋值给last位置,结束当次first搜索.
4.重复第二,三步,并在first>=last时结束,同时把key值还原到first位置。
以上完成的是一个key值的排序.以上流程一定确定好了key值的位置,同时key值将整个数据列分成左右两段.左段为(0 ~ first-1),左段的数一定都小于key,右段为(first+1 ~ last),右段的数一定都大于key.分别对左右两段再次进行快速排序,直到段大小为1为止.
优缺点:数据移动少,快速;但不稳定,当数组本身接近有序时,此时排序性能很差
复杂度:
时间复杂度:最好:O(nlog2n),最坏:O(n²)
图解
代码实现
template<class T>
void _QuickSort(T * const pdata, int first, int last, bool IsUp)
{
if (first < last)
{
T key = pdata[first];
int _first = first;
int _last = last;
if (IsUp)
{
while (_first > _last)
{
while (_first > _last)
{
if (key > pdata[_last])
{
pdata[_first] = pdata[_last];
break;
}
else
{
--_last;
}
}
while (_first > _last)
{
if (key < pdata[_first])
{
pdata[_last] = pdata[_first];
break;
}
else
{
++_first;
}
}
}
}
pdata[_first] = key;
//递归
_QuickSort(pdata, first, _first - 1, IsUp);
_QuickSort(pdata, _first + 1, last, IsUp);
}
}
template<class T>
void QuickSort(T * const pdata, size_t size, bool IsUp = true)
{
_QuickSort(pdata, 0, size - 1, IsUp); //调用
}