简介
排序算法就是根据关键字将数据(也叫记录)进行排序的过程。
稳定的排序算法:若记录1和记录2的关键字k1 == k2,在排序之前记录1就排在记录2前面。排序之后记录1仍然排在记录2前面,则这种排序算法稳定。
1. 冒泡排序
冒泡排序的基本原理是将两两相邻记录进行对比,若反序则交换,直到没有反序的相邻记录为止。
1.1 简单的冒泡排序
#include <iostream>
using namespace std;
void BubbleSort(int k[], int n)
{
int count_1 = 0, count_2 = 0;
for (int i = 0; i < n-1; i++)
{
for (int j = i+1; j < n; j++)
{
count_1++;
if (k[i] > k[j])
{
count_2++;
int tmp = k[i];
k[i] = k[j];
k[j] = tmp;
}
}
}
for (int i = 0; i < n; i++)
{
cout << k[i] << " ";
}
cout << "count_1: " << count_1 << " count_2: " << count_2 << endl;
}
int main()
{
int k[] = {2, 1, 3, 4, 5, 6};
BubbleSort(k, 6);
return 0;
}
其中,count_1记录比较次数,count_2记录交换次数。
比较次数为n(n-1)/2.
运行结果如下:
1 2 3 4 5 6 count_1: 15 count_2: 1
1.2 正宗的冒泡排序
#include <iostream>
using namespace std;
void BubbleSort(int k[], int n)
{
int count_1 = 0, count_2 = 0;
for (int i = 0; i < n-1; i++)
{
bool flag = false;
for (int j = n-1; j > i; j--)
{
count_1++;
if (k[j-1] > k[j])
{
count_2++;
int tmp = k[j-1];
k[j-1] = k[j];
k[j] = tmp;
flag = true;
}
}
if (!flag)
break;
for (int i = 0; i < n; i++)
{
cout << k[i] << " ";
}
cout << "count_1: " << count_1 << " count_2: " << count_2 << endl;
}
int main()
{
int k[] = {2, 1, 3, 4, 5, 6};
BubbleSort(k, 6);
return 0;
}
如果在一次循环中没有出现交换数据的情况,说明数据已经排好序,则退出循环。
正宗冒泡排序的循环次数,在大多数记录按序排列时,将会大大减小。
运行结果如下:
1 2 3 4 5 6 count_1: 9 count_2: 1
2. 选择排序
选择排序的基本原理是通过n-i次比较,选出n-i+1个记录中的最小/最大值,然后将最小/最大值与第i个记录交换。
#include <iostream>
using namespace std;
void SelectSort(int k[], int n)
{
int count_1 = 0, count_2 = 0;
for (int i = 0; i < n-1; i++)
{
int min_index = i;
for (int j = i+1; j < n; j++)
{
count_1++;
if (k[min_index] > k[j])
{
min_index = j;
}
}
if (min_index != i)
{
int tmp = k[i];
k[i] = min_index;
k[min_index] = tmp;
count_2++;
}
}
for (int i = 0; i < n; i++)
{
cout << k[i] << " ";
}
}
int main()
{
int k[] = {2, 1, 3, 4, 5, 6};
SelectSort(k, 6);
return 0;
}
选择排序的交换次数总是小于等于冒泡排序的比较次数的。
这次的例子刚好是二者相等。
选择排序的比较次数依然是n(n-1)/2.
运行结果如下:
1 2 3 4 5 6 count_1: 15 count_2: 1
总结
总的来说,
选择排序的效率高于冒泡排序,选择排序的交换次数少;
正宗冒泡排序的效率高于简单冒泡排序,正宗冒泡排序的比较次数有可能少。