几种排序算法的C++实现

一、复杂度比较

类别 排序方法 时间复杂度 空间复杂度 稳定性
平均情况 最好情况 最坏情况

插入

排序

直接插入 O(n^{2}) O(n) O(n^{2}) O(1) 稳定
shell排序 O(n^{1.3}) O(n) O(n^{2}) O(1) 不稳定

选择

排序

简单选择 O(n^{2}) O(n^{2}) O(n^{2}) O(1) 不稳定
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定

交换

排序

冒泡排序 O(n^{2}) O(n) O(n^{2}) O(1) 稳定
快速排序 O(nlogn) O(nlogn) O(n^{2})

O(logn)

~O(n)

不稳定
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定


二、几种排序的C++实现
1、冒泡排序
基本思想是大的数依次沉底,设置两个位置指针i和j,i从首位开始,j从末尾开始,依次比较j到i之间的数的大小,依次交换即可。设置交换标志位flag,若发生过交换,则认为已经有序,不再发生交换,代码如下:

void BubbleSort(vector &array)//O(n^2)
{
	int len = array.size();
	int flag = 1;//是否发生交换标志,默认无序即发生了交换
	for (int i = 0; (i < len) && flag; i++)
	{
		flag = 0;
		for (int j = len - 2; j >= i; j--)
		{
			if (array[j] > array[j + 1])
			{
				swap(array[j], array[j + 1]);
				flag = 1;
			}
		}
	}
}

2、简单选择排序

基本思想:从首位开始,将该位置之后最小的元素与之比较,若存在比当前位置还小的元素,则交换,直至遍历完整个数组,代码如下:

void Simple_SlectSort(vector &array)//O(n^2)
{
	//依次取出最小的放在开始无序的位置
	int len = array.size();
	int i = 0, j = 0, min = 0;
	for (i = 0; i < len; i++)
	{
		min = i;
		for (j = i + 1; j < len; j++)
		{
			if (array[min] > array[j])
				min = j;
		}
		if (i != min)
			swap(array[min], array[i]);
	}
}

3、直接插入排序

基本思想:将一个记录插到有序数组里面,开始时,将第一个元素视为有序数组。i从下标1开始(i初始下标0),取出第i位置的元素,插到前面合适的位置,使得新数组有序,代码如下:

void InsertSort(vector &array)//O(n^2)
{
	int tmp = 0;
	int len = array.size();
	for (int i = 1; i < len; i++)
	{
		int k = i;//需要插入的位置
		tmp = array[i];
		for (int j = i - 1; (j >= 0) && (array[j] > tmp); j--)
		{
			array[j + 1] = array[j];
			k = j;
		}
		array[k] = tmp;
	}
}

4、希尔排序

基本思想:先分组,再进行插入排序。根据经验,分组间隔大小gap = gap/3 + 1,代码如下:

void ShellSort(vector &array)//O(n^1.3),不稳定
{
	int tmp = 0;
	int len = array.size();
	int gap = len;

	do
	{
		gap = gap / 3 + 1;
		for (int i = gap; i < len; i += gap)
		{
			int k = i;//需要插入的位置
			tmp = array[i];
			for (int j = i - gap; (j >= 0) && (array[j] > tmp); j -= gap)
			{
				array[j + gap] = array[j];
				k = j;
			}
			array[k] = tmp;
		}

	} while (gap > 1);
	
}

5、快速排序

基本思想:通过⼀趟排序将待排记录分割成独⽴的两部分,其中⼀部分记录的关键字均⽐另⼀部分记录的关键字⼩,则可分别对这两部分记录继续进⾏排序,以达到整个序列有序的⽬的,代码如下:

void QuickSort(vector &array, int left, int right)//O(nlog2n),不稳定
{
	if (left < right)
	{
		int i = left, j = right, x = array[left];
		while (i < j && array[j] >= x)
			j--;//从右到左找到第一个小于X的数
		if (i < j)
			array[i++] = array[j];
		while (i < j && array[i] <= x)
			i++;//从左到右找到第一个大于X的数
		if (i < j)
			array[j--] = array[i];
		array[i] = x;//x放在中间
		QuickSort(array, left, i - 1);
		QuickSort(array, i + 1, right);
	}
}

6、归并排序

基本思想:是假设初始序列含有n个记录,则可以看成是n个有序的⼦序列,每个⼦序列的⻓度为1,然后两两归并,得到|n/2|(|x|表示不⼩于x的最⼩整数)个⻓度为2或1的有序⼦序列;再两两归并,如此重复,直⾄得到⼀个⻓度为n的有序序列为⽌,这种排序⽅法称为2路归并排序,代码如下:

//合并有序数组
void merge(vector &array, int left, int right, vector &res)
{
	int l_index = left;
	int l_len = (right - left + 1) / 2 + 1;
	int r_index = l_index + l_len;
	int res_index = left;
	while (l_index < left + l_len && r_index < right + 1)
	{
		if (array[l_index] <= array[r_index])
			res[res_index++] = array[l_index++];
		else
			res[res_index++] = array[r_index++];
	}
	while (l_index < left + l_len)//如果左边还有剩余
	{
		res[res_index++] = array[l_index++];
	}
	while (r_index < right + 1)//如果右边还有剩余
	{
		res[res_index++] = array[r_index++];
	}
}

void Merge_sort(vector &array, int left, int right, vector &res)
{
	if (right - left == 1)//如果区间只有两个元素则进行排序
	{
		if (array[left] > array[right])
		{
			swap(array[left], array[right]);
		}
		return;
	}
	else if (right - left == 0)//只有一个元素则不用排序
		return;
	else
	{
		//继续划分左右子区间
		Merge_sort(array, left, (right - left + 1) / 2 + left, res);
		Merge_sort(array, (right - left + 1) / 2 + left + 1, right, res);
		merge(array, left, right, res);
		for (int i = left; i <= right; i++)
			array[i] = res[i];
	}
}

7、堆排序

基本思想:堆排序是基于完全二叉树的排序方法,将待排序的序列构造成⼀个⼤顶堆。此时,整个序列的最⼤值就是堆顶的根结点。将它移⾛(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最⼤值),然后将剩余的n-1个序列重新构造成⼀个
堆,这样就会得到n个元素中的次⼤值。如此反复执⾏,便能得到⼀个有序序列,代码如下:


// 递归方式构建大根堆(len是arr的长度,index是第一个非叶子节点的下标)
void adjust(vector &arr, int len, int index)
{
	int left = 2 * index + 1; // index的左子节点
	int right = 2 * index + 2;// index的右子节点

	int maxIdx = index;
	if (left arr[maxIdx])
		maxIdx = left;
	if (right arr[maxIdx])
		maxIdx = right;
	if (maxIdx != index)
	{
		swap(arr[maxIdx], arr[index]);
		adjust(arr, len, maxIdx);
	}

}

// 堆排序
void heapSort(vector &arr, int size)
{
	// 构建大根堆(从最后一个非叶子节点向上)
	for (int i = size / 2 - 1; i >= 0; i--)
	{
		adjust(arr, size, i);
	}

	// 调整大根堆
	for (int i = size - 1; i >= 1; i--)
	{
		swap(arr[0], arr[i]);           // 将当前最大的放置到数组末尾
		adjust(arr, i, 0);              // 将未完成排序的部分继续进行堆排序
	}
}

8、基数排序

基本思想:按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。

//寻找数组中最大数的位数作为基数排序循环次数
int KeySize(int a[], int n){
    int key = 1;
    for(int i=0;i0){
            temp++;
            r*=10;
        }
        key = (temp>key)?temp:key;
    }
    return key;
}

//基数排序
void RadixSort(int a[], int n){
    int key = KeySize(a,n);
    int bucket[10][10]={0};
    int order[10]={0};
    for(int r = 1;key>0;key--,r*=10){
        for(int i=0;i

参考资料:

1、https://www.cnblogs.com/wuxiangli/p/6399266.html

2、https://www.cnblogs.com/wanglei5205/p/8733524.html

3、https://www.cnblogs.com/cityflickr/p/3896109.html

4、《大话数据结构》——程杰

你可能感兴趣的:(C/C++)