今天天气不错,最近看了一下大神们的排序总结,我也给自己总结一下吧。
说明:代码中为了说明算法的流程,对于输入的参数没有进行检验。(事实上是需要的),并且默认排序为非递减数组(升序)。
内部排序和外部排序
- 根据排序过程中涉及的存储器不同,可以讲排序方法分为两大类:一类是内部排序,指的是待排序的几率存放在计算机随机存储器中进行的排序过程;另一类的外部排序,指的是排序中要对外存储器进行访问的排序过程。
- 内部排序是排序的基础,在内部排序中,根据排序过程中所依据的原则可以将它们分为5类:插入排序、交换排序、选择排序、归并排序和基数排序;根据排序过程的时间复杂度来分,可以分为三类:简单排序、先进排序、基数排序。
评价排序算法优劣的标准主要是两条:一是算法的运算量,这主要是通过记录的比较次数和移动次数来反应;另一个是执行算法所需要的附加存储单元的的多少。(来自度娘)
对于每种算法的来历我就不废话了,详情可以百度,bing, google。。。。
- 插入排序
- 冒泡排序
- 选择排序
- 归并排序
- 快速排序
1.插入排序
插入排序,第一个元素作为有序数组的第一个元素,从数组的第二个元素开始,依次将元素放入已经有序的数组中,如果小于则向前移动,如果大于则停止放在当前的位置。
e.g. * 5 4 3 2 1* 是原始数组
初始化 5 待进入数字4
第一次排序完成 4 5
第二次排序完成 3 4 5
第三次排序完成 2 3 4 5
第四次排序完成 1 2 3 4 5 搞定
//插入排序
//size_t是std命名空间下的 unsigned int
template <typename T>
void Insertion_Sorting(T *arrayT, size_t length)
{
for (unsigned int i = 1; i < length; i++)
{
int j = i - 1;//有序数组的最后一个元素
T key = arrayT[i];//待排序元素
while (j >= 0 && arrayT[j] > key)//保证不越界 当j循环到-1时,由于[[短路求值]],不会运算arrayT[-1]
{
arrayT[j + 1] = arrayT[j];//如果小于则大数向后移动
j--;//因为j-- 所以循环结束不满足条件的时候 j可能<0 或者 arrayT[j] < key
}
arrayT[j + 1] = key; //这里需要+1 原因是while 里面的j--
}
}
时间复杂度为O(n^2)
2.冒泡排序
冒泡排序从第一个开始,如果大于后面的数字就往后移一位,如果遇到比自己大的则不交换,但是将大的作为下次移动的对象。(循环是从n 到1, 即从末尾到第一个)
e.g. * 4 3 5 2 1* 是原始数组
第一次排序完成 3 4 2 1 5
第二次排序完成 3 2 1 4 5
第三次排序完成 2 1 3 4 5
第四次排序完成 1 2 3 4 5 搞定
template <typename T>
void Bubble_Sort(T *arrayT, size_t length)
{
for (unsigned int i = 0; i != length - 1; i++)
{
for (unsigned int j = 0; j + i != length - 1; j++)
{
if (arrayT[j] > arrayT[j + 1])//如果大于后面的数就交换位置,否则从后一个数接着比较
{
T temp = arrayT[j];
arrayT[j] = arrayT[j + 1];
arrayT[j + 1] = temp;
}
}
}
}
冒泡排序最好的时间复杂度为O(n)
冒泡排序总的平均时间复杂度为 O(n^2)
3.选择排序
选择排序就是一趟又一趟找到最小(大)的放在最小(大)的位置即可。。。
e.g. * 4 3 5 2 1* 是原始数组
第一次排序完成 1 3 5 2 4
第二次排序完成 1 2 5 3 4
第三次排序完成 1 2 3 5 4
第四次排序完成 1 2 3 4 5 搞定
template <typename T>
void Selection_Sort(T *arrayT, size_t length)
{
for (unsigned int i = 0; i < length; i++)
{
int min = i;
for ( unsigned int j = i + 1; j < length; j++)
{
if (arrayT[min] > arrayT[j])
{
min = j;//记录最小值
}
}
T temp = arrayT[i];
arrayT[i] = arrayT[min];
arrayT[min] = temp;
}
}
4.归并排序
选择排序就是一趟又一趟找到最小(大)的放在最小(大)的位置即可。。。
e.g. * 5 4 3 2 1* 是原始数组
[0-4]拆分
[0-2][3-4] 合并[0-4] 第四次合并
左边
[[0-1][2-2]] 合并[0-2] 第二次合并
[[ [0-0] [1-1]] 合并[0-1] 第一次合并
右边
[[3-3][4-4]] 合并[3-4] 第三次合并
[[5 4] 3] [2 1]]
第一次排序完成 [4 5] 3 2 1
第二次排序完成 [3 4 5] 2 1
第三次排序完成 3 4 5 [1 2]
第四次排序完成 [1 2 3] [4 5] 搞定
template <typename T>
void Merge(T *sourceArray, T *temp, int Start_Index, int Mid_Index, int End_Index)
{
int i = Start_Index, j = Mid_Index + 1, k = Start_Index;
while (i != Mid_Index + 1 && j != End_Index + 1)//数组 前半部分和后半部分合并
{
if (sourceArray[i] > sourceArray[j])
{
temp[k++] = sourceArray[j++];
}
else
{
temp[k++] = sourceArray[i++];
}
}
while (i != Mid_Index + 1)//剩余的元素
{
temp[k++] = sourceArray[i++];
}
while (j != End_Index + 1)//剩余的元素
{
temp[k++] = sourceArray[j++];
}
for (int i = Start_Index; i != End_Index + 1; i++)//拷贝回去
{
sourceArray[i] = temp[i];
}
}
template <typename T>
void Merge_Sort(T *sourceArray, T *temp, int Start_Index, int End_Index)
{
if (Start_Index < End_Index)
{
int Mid_Index = (Start_Index + End_Index) / 2;
Merge_Sort(sourceArray, temp, Start_Index, Mid_Index);//尾巴一直除以2
Merge_Sort(sourceArray, temp, Mid_Index + 1, End_Index);//头一直除以2
Merge(sourceArray, temp, Start_Index, Mid_Index, End_Index);
}
}
5.快速排序
快速排序就是每次选取一个枢轴值,利用二分法将当前数组中大于枢轴值得元素放在后面,否则放在前面。在小于和大于的区间再进行划分区域再排序。
如果是逆序数组,快排会退化为O(n^2)
e.g. * 5 4 3 2 1* 是原始数组
第一次排序完成 —- 枢轴值是5,1 4 3 2 5
第二次排序完成 —- 枢轴值是1 , 1 4 3 2 5
第三次排序完成 —- 枢轴值是4,1 2 3 4 5
第四次排序完成 —- 枢轴值是3,1 2 3 4 5 搞定
e.g. * 2 4 3 5 1 * 是原始数组
第一次排序完成 —- 枢轴值是2, 1 2 3 5 4
第二次排序完成 —- 枢轴值是 3 , 1 2 3 5 4
第二次排序完成 —- 枢轴值是 5 , 1 2 3 4 5 搞定
template <typename T>
void Quick_Sort(T *arrayT, int Start_Index, int End_Index)
{
if (Start_Index < End_Index)//注意这里是小于!!!!!!!
{
int first = Start_Index;//左边界
int last = End_Index;//右边界
T key = arrayT[first];//枢轴值
while (first < last)//左右边界 相遇的地方
{
while (first < last && arrayT[last] >= key)//从右边找比枢轴值所小的下标
{
last--;
}
arrayT[first] = arrayT[last];//将小值放在小位置
while (first < last && arrayT[first] <= key)//从左边选择比枢轴值大的下标
{
first++;
}
arrayT[last] = arrayT[first];//将大值放在大位置
}
arrayT[first] = key;//枢轴值的位置
Quick_Sort(arrayT, Start_Index, first - 1);//左边再排序
Quick_Sort(arrayT, first + 1, End_Index);//右边再排序
}
}
快排还有好多升级版,三分快排,随机枢值快排等,大家有兴趣可以查找相关资料哟。。。
看到这里的都是真爱。。。。排序算法那么多,这次只写了寥寥的几个,有时间会接着写一些常用的东西的。
全文的代码放在这里了大家来找BUG呀!
戳我—带你去整个代码的地方,欢迎来给我找BUG
测试环境 CodeBlocks 16.01