交换类排序其实一般就两种,一个就是冒泡排序,另一个就是快速排序,比较两张算法,肯定是快排效率较高,原因很简单,对于冒泡排序只能与相邻的元素进行比较,互换时候只能消除一个逆序,但是快排通过两个不相邻的元素交换,可以消除待排序记录中的多个逆序,即后面的元素不需要再做无谓的逆序了。
(1)冒泡排序比较简单,简单说下算法思路:
过程:
a. 从第一个记录开始和第二个记录比较,如果大于第二个记录就交换,否则就不交换,比较下一个元素,依次循环下去,因此第一趟就会找到最大的值放到数组的最后面n-1的位置上。
b. 然后用相同的方式在前n-2个元素中得出最大值放在n-2位置。
c. 重复上述操作,知道全部比较完成。
void BullSort(int a[], int length)
{
for (size_t i = 0; i < length - 1; i++)
{
for (size_t j = 0; j < length-1-i; j++)
{
if (a[j] > a[j + 1])
{
swap(a[j], a[j + 1]);
}
}
}
}
性能分析: T(n) = O( n ^2),k空间复杂度 S(n) = O(1)
(2)快速排序:该算法是有英国的计算机学家Hore提出的,对于个人来说非常喜欢快速排序,不仅仅因为是其算法效率比较高,最主要的原因还是他的这种思想很好,值得借鉴,。
算法思路:
a. 首先需要需要设置两个人标志位:low,high来记录数组的头和末尾,并取第一个节点作为基准a[low]保存在临时变量a[0]中.
b. 然后从有右向左依次寻找第一个小于a[0]的值,然后放在a[low]中,此时low++;
c. 然后从有low向右依次寻找第一个大于a[0]的值,然后放在a[high]中,此时high++;
d. 依次循环知道high== low循环结束。把a[0放在a[high]中。
e. 至此第一趟排序结束,找到分支点,此时把数组分为两部分,然后分对左右两部分进行上述操作,最后排序完成。
例如:
代码如下:
int QKPass(int a[], int low, int high)
{
a[0] = a[low];
while (low < high)
{
//从右寻找第一个小于a[0]得数
while ( high > low && a[high] > a[0])
{
high--;
}
if (high > low)
{
a[low] = a[high];
low++;
}
//从左寻找第一个大或等于于a[0]得数
while (high > low && a[low] < a[0])
{
low++;
}
if (high > low)
{
a[high] = a[low];
high--;
}
}
a[low] = a[0];
return low;
}
void QKSort(int a[],int low,int high)
{
if (low < high)
{
int pos = QKPass(a, low, high);//找到分支点
QKSort(a,low, pos - 1);
QKSort(a, pos+1, high);
}
}
性能分析: T(n) = O( nlog2(n)),k空间复杂度 S(n) = O(1)
小结:
排序算法 | 时间复杂度 | 最好情况 | 最坏情况 | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
冒泡排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
快速排序 | O(nlog2(n)) | O(nlog2(n)) | O(n^2) | S(n)=O(log2(n))最坏情况:S(n)=O(n) | 不稳定 |