常见的5种排序算法代码的C++实现

1、冒泡排序
平均时间复杂度:O(n^2)
最差时间复杂度:O(n^2)
空间复杂度:O(1)
是否稳定:
原理:它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

// 当数列本身有序,只需要扫描一遍即可
void BubbleSortFlag(vector<int>& vec) {
    for (int i = 0; i < vec.size() - 1; i++) {
        bool swapFlag = true;
        for (int j = 0; j < vec.size() - 1 - i; j++) {
            if (vec[j] > vec[j + 1]) {
                swap(vec[j], vec[j + 1]);
                swapFlag = false;
            }
        }
        if (swapFlag) break;
    }
}

2、插入排序
平均时间复杂度:O(n^2)
最差时间复杂度:O(n^2)
空间复杂度:O(1)
是否稳定:
原理:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

//从(右侧)无序序列中顺序选取数据插入到(左侧)有序序列中
void InsertSort(vector<int>& vec) {
	// 默认第一个元素是有序的,只需要对剩下的 n-1 个数进行插入操作,即扫描n-1次,所以,只需要从 i = 1 开始
	for (int i = 1; i < vec.size(); i++) {
		int temp = vec[i];
		int j=i-1;
		// 从有序序列尾部开始,方便挪动,i 之前都是有序的
		for (; j >= 0; j--) {//查找插入的位置
			if(vec[j]>temp) vec[j + 1] = vec[j];//数据移动
			else break;
		}
		vec[j + 1] = temp; // 插入
	}
}

3、选择排序
平均时间复杂度:O(n^2)
最差时间复杂度:O(n^2)
空间复杂度:O(1)
是否稳定:
原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

void SelectSort(vector<int>& vec) {
	// 遍历n-1次
	for (int i = 0; i < vec.size() - 1; i++) {
		int minn = i;
		for (int j = i + 1; j < vec.size(); j++) {//查找最小值所在的位置
			if (vec[j] < vec[minn]) minn = j;
		}
		if(minn != i)
			swap(vec[minn], vec[i]); //  把最值放在起始位置
	}
}

4、归并排序
平均时间复杂度:O(nlog2n)
最差时间复杂度:O(nlog2n)
空间复杂度:O(n)
是否稳定:
原理:采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。分割:递归地把当前序列平均分割成两半。集成:在保持元素顺序的同时将上一步得到的子序列集成到一起(归并)。

//合并两个有序数组,下标分别为 l~mid 以及 mid+1~r
void merge(vector<int>& vec, int l, int mid, int r) {
	vector<int> temp(r - l + 1);
	int i=l,j=mid+1,k=0;
	while (i <= mid && j<=r) {
		if (vec[i] < vec[j]) {
			temp[k++] = vec[i++];
		}
		else {
			temp[k++] = vec[j++];
		}
	}
	while (i <= mid) {
		temp[k++] = vec[i++];
	}
	while (j <= r) {
		temp[k++] = vec[j++];
	}
	//将temp中的内容copy回vec[l...r]中
	for(i = 0; i < r-l+1; i++){
		vec[l+i] = temp[i];
	}
}

//传统递归分治
void MergeSort(vector<int>& vec, int l, int r) {
	if (l >= r) return;
	
	int mid = l + (r - l) / 2;
	MergeSort(vec, l, mid);
	MergeSort(vec, mid + 1, r);
	
	//将vec[1...mid]和vec[mid+1...r]合并为vec[l...r]
	merge(vec, l, mid, r);
}

5、快速排序
平均时间复杂度:O(nlog2n)
最差时间复杂度:O(n^2)
空间复杂度:O(log2n)
是否稳定:
tip:数组小的时候采用插入排序效果更高 。快排每次递归都有一个数放在最终的位置。

// 先从右开始向左寻找比 pivot 小的数,然后从左向右寻找比 pivot 大的数,然后交换,重复以上步骤,直到i >= j
int partition(vector<int>& vec, int l, int r) {
	int pivot = vec[l];
	int i = l, j = r; // i = l+1 不可以,当 l+1=r 的时候, 1、2两个数会发生交换,实际上不应该交换,而i=l,因为计算j的位置,i的位置就不会发生变换,即使交换也是原地交换
	while (i < j) {
		while (i < j && vec[j] >= pivot) j--;
		while (i < j && vec[i] <= pivot) i++;	// 为什么等于号,因为 i 从l开始,和自身比较,如果不考虑相等,i 少前进一位
		if (i < j) swap(vec[i], vec[j]);
	}
	if (l != i) {
		vec[l] = vec[i];
		vec[i] = pivot;
	}
	return i;
}
void QuickSort(vector<int>& vec, int l, int r) {
	if (l >= r) return;
	int q = partition(vec, l, r);//获取分区点下标

	QuickSort(vec, l, q-1);
	QuickSort(vec, q + 1, r);
}
void sort(vector<int>& vec) {
	QuickSort(vec, 0, vec.size()-1);
}

你可能感兴趣的:(C++,排序算法,c++,算法)