排序算法的总结:冒泡排序,选择排序,快速排序,插入排序,归并排序,堆排序,基数排序,桶排序
1、冒泡排序
冒泡排序是最简单的排序之一了,其大体思想就是通过与相邻元素的比较和交换来把小的数交换到最前面,或者通过与相邻元素的比较和交换来把大的数交换到最最后面。冒泡排序的时间复杂度为O(n^2)。
//冒泡排序
template<class T>
void bubbleSort(T a[], int n)
{
if (a ==NULL || n <= 0)
return 0;
for (int i = 0; i < n; i++)
{
for (int j = n-1; j >i; j--)
{
if (a[j] < a[j -1])
swap(a[j], a[j -1]);
}
}
}
2、选择排序
选择排序是从一组数据中,先找到其中最小的值记住下标索引,放到第0个位置,接着找到第二个最小值,放到第1个位置。以此类推。选择排序可以看成冒泡排序的优化,因为其目的相同,只是选择排序只有在确定了最小数的前提下才进行交换,大大减少了交换的次数。选择排序的时间复杂度为O(n^2)。
//选择排序
template<class T>
void SelectSort(T a[], int n)
{
if (a==NULL || n <= 0)
return 0;
for (int i = 0; i < n-1; i++)
{
minIndex = 0;
for (int j = i+1; j < n; j++)
{
if (a[j]<a[minIndex])
minIndex=j
}
if (minIndex!=i)
swap(a[i], a[minIndex]);
}
}
3、快速排序
这里重要的说明一下快速排序,快速排序思想是来自冒泡排序,快速排序(Quicksort)是对冒泡排序的一种改进。
它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
假设用户输入了如下数组:
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 5 | 1 | 6 | 2 | 8 | 9 |
我们使i=0, j=5, k=5(支点a[0])。
我们要把所有比k小的数移动到k的左面,所以我们可以开始寻找比k小的数,从j开始,从右往左找,不断递减变量j的值,我们找到第一个a[3]的数据比5小,于是把数据a[3]赋值给a[0], 数据如下:
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 2 | 1 | 6 | 2 | 8 | 9 |
i=0 j=3 k=5
接着,开始第二次比较,这次要变成找比k大的了,而且要从前往后找了。递加变量i,发现a[2]的数据是第一个比k大的,于是将a[2]的值赋值给a[j];数据状态变成下表:
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 2 | 1 | 6 | 6 | 8 | 9 |
i=2 j=3 k=5
此时i和j没有交汇,说明数的两边没有比较完,接着找比k小的数,接着j--,此时发现i=j,数据状态变成下表:
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 2 | 1 | 6 | 6 | 8 | 9 |
I=2 j=2 k=5;
最后跳出循环,另a[j]=k,数据的状态如下:
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 2 | 1 | 5 | 6 | 8 | 9 |
这时可以看到5的左边比5不大于5,5的右边不小于5,
然后,对k两边的数据,再分组分别进行上述的过程,直到不能再分组为止(只有一个数据)。
上面数据演示的算法是优化后的,优化前的算法是每次在右边j位置找到比支点k小的,则直接交换swap(a[i],a[j]),每次在左边i位置找到比支点k大的的,则直接交换swap(a[i],a[j])swap中声明了临时变量,会增加程序的空间大小,。
快速排序的代码如下:
//快速排序
template<class T>
void Qsort(T a[], int low, int high)
{
//high为a的最高索引
if (low >= high)
return;
int first = low;
int last = high;
int key = a[first];/*用字表的第一个记录作为枢轴*/
while (first < last)
{
while (first < last && a[last] >= key)
{
--last;
}
a[first] = a[last];/*将比第一个小的移到低端*/
while (first < last && a[first] <= key)
{
++first;
}
a[last] = a[first];
/*将比第一个大的移到高端*/
}
a[first] = key;/*枢轴记录到位*/
Qsort(a, low, first - 1);
Qsort(a, first + 1, high);
}
4、插入排序
插入排序不是通过交换位置而是通过比较找到合适的位置插入元素来达到排序的目的的。对5,3,8,6,4这个无序序列进行简单插入排序,首先假设第一个数的位置时正确的,没必要整理。然后3要插到5前面,把5后移一位,变成3,5,8,6,4.想一下整理牌的时候应该也是这样吧。然后8不用动,6插在8前面,8后移一位,4插在5前面,从5开始都向后移一位。注意在插入一个数的时候要保证这个数前面的数已经有序。简单插入排序的时间复杂度也是O(n^2)。
//插入排序
template<class T>
void insertSort(T arr[],int n)
{
for (int i = 1; i<n; i++)
{ //假设第一个数位置时正确的;要往后移,必须要假设第一个。
int j = i;
int target = arr[i]; //待插入的
//后移
while (j > 0 && target < arr[j - 1]) {
arr[j] = arr[j - 1];
j--;
}
//插入
arr[j] = target;
}
}