交换排序:根据想要的排列的顺序,比如从小到大或者从大到小,通过不断的元素的互相交换,最终达到有序。
1、冒泡排序:
冒泡排序可能是最直观的排序了,每个元素依次和它后面的元素进行比较,不断把该元素和将比它大/小的元素进行交换,最终得到这个位置应该的元素。
显然冒泡排序的时间复杂度是:O(N - 1) + O(N - 2) + ...... + O(1) -> O(N * N),而且不存在什么最好最坏情况,因为冒泡排序总是得交换;空间复杂度为1。
另外显然冒泡排序是稳定排序。
buddle.h(类声明):
#include <stdlib.h>
#include <vector>
#include <iostream>
template<class T> class buddler {
std::vector<T> data;
public:
buddler(std::vector<T> _data);
buddler(T *_data, int size);
~buddler(){data.clear();}
void bsort();
void show(bool direct);
};
buddle_func.h(类实现):
#include "buddle.h"
template<class T> buddler<T>::buddler (std::vector<T> _data) {
data = _data;
bsort();
}
template<class T> buddler<T>::buddler (T *_data, int size) {
for (int i = 0; i < size; i++) {
data.push_back(_data[i]);
}
bsort();
}
template<class T> void buddler<T>::bsort () {
for (int i = 0; i < data.size(); i++) {
for (int j = i; j < data.size(); j++) {
if (data[i] >= data[j]) {
T tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
}
}
}
template<class T> void buddler<T>::show (bool direct) {
if (direct) {
for (int i = 0; i < data.size(); i++) {
std::cout << data[i];
if (i != data.size() - 1) {
std::cout << ", ";
}
}
} else {
for (int i = data.size() - 1; i >= 0; i--) {
std::cout << data[i];
if (i != data.size() - 1) {
std::cout << ", ";
}
}
}
std::cout << std::endl;
}
buddle.cpp(测试程序):
#include "buddle_func.h"
int main () {
int *testdata = new int[3000 * sizeof(int)];
srand((int)time(0));
for (int i = 0; i < 3000; i++) {
testdata[i] = rand();
}
buddler<int> bsorter(testdata, 3000);
bsorter.show(1);
delete []testdata;
return 0;
}
2、快速排序:
快速排序是对冒泡排序的重大改进,也是使用比较广泛的排序方式。原理:选一条数据作为标杆,把其他数据中比它大的和比它小的分为两个部分,然后继续对这两部分进行同样的事情,直到所有的部分都排序完成。
从原理可知显然快速排序非常适合递归进行的,时间复杂度 = 选标杆并拆分次数 * (N - 1) -> 接近于O(N * logN)。O(N * logN)也是最好的情况,即每次数据都能被标杆数据分为数量相同的两部分。如1、2、3、4、5、6、7,以4为标杆,分为1、2、3和5、6、7,然后又分别以2、6再分,形成完美的"二分",选标杆并拆分的次数最少,达到logN。
快速排序的最坏情况就是,每次选作为标杆的数据是最大/小值,导致只分出来比它大或小的部分,比如1、2、3、4、5、6、7,依次以7、6、5...的顺序作为每次的标杆数据,这实质上和冒泡排序是一样的了。有种说法是数据越有序快速排序效果越差,往往确实是,因为快速排序的实现中往往以首/尾元素作为每次的标杆。
快速排序明显是不稳定的,因为相同的一个值可能由于标杆数据选取的不同,被分在了不同的partition里。
另外快速排序的空间复杂度为1。
qsort.h(类声明)
#include <iostream>
#include <stack>
#include <vector>
template<class T> class qsorter {
std::vector<T> data;
int partition(int start, int end);
void swap(int i, int j);
public:
qsorter(T *_data, int size);
qsorter(std::vector<T> _data);
~qsorter(){data.clear();}
void qsort(int start, int end);
void qsort();
void qsort_unreverse();
void show(bool direct);
};
qsort_func.h(类定义)
#include "qsort.h"
template<class T> qsorter<T>::qsorter (std::vector<T> _data) {
data = _data;
qsort();
}
template<class T> qsorter<T>::qsorter (T *_data, int size) {
for (int i = 0; i < size; i++) {
data.push_back(_data[i]);
}
qsort_unreverse();
}
template<class T> void qsorter<T>::swap (int i, int j) {
if (i != j) {
T tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
}
template<class T> int qsorter<T>::partition (int start, int end) {
int i = start, j = start;
T lastval = data[end];
for (; i < end; i++) {
if (data[i] <= lastval) {
swap(i, j);
j++;
}
}
swap(end, j);
return j;
}
template<class T> void qsorter<T>::qsort_unreverse () {
std::stack<T> stk;
int idx = partition(0, data.size() - 1);
if (idx > 0) {
stk.push(0);
stk.push(idx - 1);
}
if (idx < data.size() - 1) {
stk.push(idx + 1);
stk.push(data.size() - 1);
}
while (!stk.empty()) {
int start, end;
end = stk.top();
stk.pop();
start = stk.top();
stk.pop();
int mididx = partition(start, end);
if (mididx > start) {
stk.push(start);
stk.push(mididx - 1);
}
if (end > mididx) {
stk.push(mididx + 1);
stk.push(end);
}
}
}
template<class T> void qsorter<T>::qsort (int start, int end) {
if (start < end) {
T lastval = data[end];
int i = start, j = start;
for (; i < end; i++) {
T curval = data[i];
if (curval <= lastval) {
swap(i, j);
j++;
}
}
swap(end, j);
qsort(start, j - 1);
qsort(j + 1, end);
}
}
template<class T> void qsorter<T>::qsort () {
int start = 0, end = data.size() - 1;
qsort(start, end);
}
template<class T> void qsorter<T>::show (bool direct) {
if (direct) {
for (int i = 0; i < data.size(); i++) {
std::cout << data[i];
if (i != data.size() - 1) {
std::cout << ", ";
}
}
} else {
for (int i = data.size() - 1; i >= 0; i--) {
std::cout << data[i];
if (i != 0) {
std::cout << ", ";
}
}
}
std::cout << std::endl;
}
qsorttest.cpp(测试程序)
#include "qsort_func.h"
#include <stdlib.h>
int main () {
int *testdata = new int[sizeof(int) * 30];
srand((int)time(0));
for (int i = 0; i < 30; i++) {
testdata[i] = rand() % 100;
}
qsorter<int> quicksorter(testdata, 30);
quicksorter.show(1);
delete []testdata;
return 0;
}
注意类定义中包括递归和非递归的快速排序实现。一般来说递归程序改造为非递归程序,需要用一个堆栈实现,程序里用STL的stack实现,道理完全一样,就是把递归会传入的参数改成放在栈里就行了。
交换排序还包括所谓的"鸡尾酒排序 奇偶排序 梳子排序 侏儒排序 臭皮匠排序 Bogo排序",但都没有快速排序简单有效。