QuickSort

思想

分治。选一个pivot,将比pivot小的元素放在左边,比pivot大的元素放在右边,对左右两个子数组递归调用QuickSort。

实现

int randomNum(int x, int y) {
		srand(time(0));  // use system time as seed
		return x + rand() % (y - x + 1);
}

int partition(vector<int>& nums, int l, int r) {
		int pivotIndex = randomNum(l, r);
		swap(nums[pivotIndex], nums[r]);

		int smaller = l - 1;
		for (int i = l; i < r; ++i) {
			if (nums[i] <= nums[r]) {
				++smaller;
				swap(nums[smaller], nums[i]);
			}
		}
		++smaller;
		swap(nums[smaller], nums[r]);
		return smaller;
}

void QuickSort(vector<int>& nums, int low, int high) {
		if(low < high) {
				int pivotPos = partition(nums, low, high);
				QuickSort(nums, low, pivotPos - 1);
				QuickSort(nums, pivotPos + 1, high);
		}
}


int partition(vector<int>& num, int low, int high) {
	int pivot = num[low];
	while (low < high) {
		while (low < high && num[high] >= pivot) {
			--high;
		}
		num[low] = num[high];
		while (low < high && num[low] <= pivot) {
			++low;
		}
		num[high] = num[low];
	}
	num[low] = pivot;
	return low;
}


void qSort(vector<int>& num, int low, int high) {
	if (low < high) {
		int pivot = partition(num, low, high);
		qSort(num, low, pivot - 1);
		qSort(num, pivot + 1, high);
	}
}

// 非递归,用栈保存要操作的范围的下标
void qSortNotR(vector<int>& num, int low, int high) {
	stack<int> s;
	s.push(low);
	s.push(high);

	while (!s.empty()) {
		int r = s.top();
		s.pop();
		int l = s.top();
		s.pop();
		int pivotPos = partition(num, l, r);
		if (l < pivotPos - 1) {
			s.push(l);
			s.push(pivotPos - 1);
		}
		if (pivotPos + 1 < r) {
			s.push(pivotPos + 1);
			s.push(r);
		}
	}
}

性能

划分的两个子问题规模分别为0和n时,时间复杂度最坏为(O(n^2))
两个子问题规模相同时,时间复杂度最好为(O(nlgn)),平均性能更接近最好情况。
假设输入数据的所有排列不是等概率的,那么为了避免最坏情况的发生,选择pivot可以随机进行,这样被pivot分开的两个子问题规模会接近(n/2)

复杂度的证明既可以用主定理,也可以自己推导,在最优情况下:

[T(n)=2T(n/2)+n \ T(n)=2(2T(n/4)+n/2)+n=4T(n/4)+2n \ T(n)=4(2T(n/8)+n/4)+2n=8T(n/8)+3n \ ... \ T(n)=nT(1)+nlogn=n+nlogn ]

原文地址:https://www.cnblogs.com/EIMadrigal/p/11524840.html