排序1:交换排序(冒泡排序+快速排序)

交换排序:根据想要的排列的顺序,比如从小到大或者从大到小,通过不断的元素的互相交换,最终达到有序。

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排序",但都没有快速排序简单有效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值