基于《啊哈!算法》的学习
桶排序
#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>
using namespace std;
int main(void)
{
const vector<int> input_data = { 5, 3, 5, 8, 2 }; //输入数据
const int max_num = 10; //最大的整数
//输出原数据
cout << "原始:";
ostream_iterator<int> o_iter(cout, " ");
copy(input_data.begin(), input_data.end(), o_iter);
cout << endl;
vector<int> flags(max_num + 1, 0); //标记数组(桶)
for (const auto data : input_data)
++flags[data]; //进行桶计数(可以边输入边计数)
cout << "排序(从小到大):";
for (int i = 0; i < flags.size(); ++i)
{
int flag_count = flags[i];
while (flag_count--)
cout << i << ' ';
}
cout << endl;
cout << "排序(从大到小):";
for (int i = flags.size() - 1; i >= 0; --i)
{
int flag_count = flags[i];
while (flag_count--)
cout << i << ' ';
}
cout << endl;
return 0;
}
时间复杂度为O(M+N)
,M为桶的个数,N为待排序的个数。
桶排序1956年开始被使用,该算法的基本思想由E.J.Issac
和R.C.Singleton
提出来的。
真正的桶排序算法更加复杂。
冒泡排序
冒泡排序的基本思想:每次比较两个相邻的元素,如果它们的顺序错误就把它们交换过来。
如果有n个数进行排序,只需将n-1个数归位(进行n-1趟操作)。
#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>
using namespace std;
int main(void)
{
const vector<int> input_data = { 8, 100, 50, 22, 15, 6, 1, 1000, 999, 0 };
//输出原数据
cout << "原始:";
ostream_iterator<int> o_iter(cout, " ");
copy(input_data.begin(), input_data.end(), o_iter);
cout << endl;
vector<int> data1 = input_data;
cout << "排序(从小到大):";
for (int i = 0; i < data1.size() - 1; ++i) //控制n-1次
{
for (int j = 0; j < data1.size() - i - 1; ++j) //减1为了不越界(访问j+1)
{
if (data1[j] > data1[j + 1])
{
int temp = data1[j];
data1[j] = data1[j + 1];
data1[j + 1] = temp;
}
}
}
copy(data1.begin(), data1.end(), o_iter);
cout << endl;
vector<int> data2 = input_data;
cout << "排序(从大到小):";
for (int i = 0; i < data2.size() - 1; ++i)
{
for (int j = 0; j < data2.size() - i - 1; ++j)
{
if (data2[j] < data2[j + 1])
{
int temp = data2[j];
data2[j] = data2[j + 1];
data2[j + 1] = temp;
}
}
}
copy(data2.begin(), data2.end(), o_iter);
cout << endl;
return 0;
}
冒泡排序的核心部分是双重嵌套循环,时间复杂度为O(N^2)
。
冒泡排序1956年有人开始研究,但是复杂度太高不推荐,Donald E.Knuth(高德纳,1974年图灵奖获得者)——冒泡排序除了它迷人的名字和导致了某些有趣的理论问题这一事实之外,似乎没有什么值得推荐的。
快速排序
快速排序之所以比较快,是因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样只能在相邻的数之间进行交换,交换的距离就大得多。因此,总的比较和交换次数就少了,速度自然就提高了。
当然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度是O(N^2)
,它的平均时间复杂度为O(NlogN)
。
快速排序是基于“二分”的思想。
#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>
using namespace std;
void quick_sort(vector<int> & data, int left, int right)
{
if (left < right) //至少是两个数
{
int p = data[left]; //取最左边为基准数
int i = left, j = right;
while (i < j)
{
while (data[j] > p && i < j)
--j;
while (data[i] <= p && i < j)
++i;
if (i < j) //i和j没有相遇,交换
{
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
}
data[left] = data[i];
data[i] = p;
quick_sort(data, left, i - 1);
quick_sort(data, i + 1, right);
}
}
int main(void)
{
vector<int> input_data = { 6, 1, 2, 7, 9, 3, 4, 5, 10, 8 };
//输出原数据
cout << "原始:";
ostream_iterator<int> o_iter(cout, " ");
copy(input_data.begin(), input_data.end(), o_iter);
cout << endl;
cout << "排序(从小到大):";
quick_sort(input_data, 0, input_data.size() - 1);
copy(input_data.begin(), input_data.end(), o_iter);
cout << endl;
return 0;
}