几种排序算法的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<int> &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<int> &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<int> &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<int> &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<int> &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<int> &array, int left, int right, vector<int> &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<int> &array, int left, int right, vector<int> &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<int> &arr, int len, int index)
{
	int left = 2 * index + 1; // index的左子节点
	int right = 2 * index + 2;// index的右子节点

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

}

// 堆排序
void heapSort(vector<int> &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;i<n;i++){
        int temp = 1;
        int r = 10;
        while(a[i]/r>0){
            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<n;i++){
             int lsd = (a[i]/r)%10;
             bucket[lsd][order[lsd]++]=a[i];
        }

        int k = 0;
        for(int i = 0;i<10;i++){
            if(order[i]!=0){
                for(int j = 0;j<order[i];j++)
                    a[k++]=bucket[i][j];
            }
            order[i]=0;
        }
    }
}

参考资料:

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、《大话数据结构》——程杰

几种常见排序 基于比较的排序算法: 下界是 nlgn 1.1 SelectionSort:每次选出最下的元素,放在当前循环最左边的位置。 1.2 BubbleSort:每次比较相邻的两个数,使得最大的数像气泡一样冒到最右边。 1. 3 InsertionSort:每次拿起一个数,插入到它左边数组的正确位置。 1.4 QuickSort:选择一个数,作为标准,小于它的放在左边,大于它的放在右边。并把它放在中间;递归地对左右子数组进行排序实现时:1. 确定递归结束条件,初始化左右游标, 选择标准数; 2. while循环,do while实现两个游标同时向中间移动,置换; 3. 置换标准数和右边游标所指的数; 4. 递归调用,对左右子数组进行排序。 1. 5 HeapSort:用最大堆实现实现时:建堆:置换堆顶元素和最后一个元素,堆大小减少,保持新的堆为最大堆; 保持最大堆: 从底向上依次保持最大堆,从第一个父节点到根部。 1.6 MergeSort:拆分数组,递归实现排序,二路归并。用哨兵来阻止游标的越界。 线性时间运行的算法: 1.7 CountingSort: 假设数据分布在0到k之间的。对于每个输入x,确定出小于x的数的个数。假设小于x的数有17个,那么x就应该在第18个输出位置。 1. 8 Radix sort(基数排序):从最低位开始,每位采用稳定的排序算法(如计数排序)。 1.9 Bucket sort:当输入数据比较均匀时采用。 先将数据区间分为n个桶,把数据分放到对应的桶中;对桶内的数据采用插入排序;再把各个桶的排序结果串起来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值