各排序算法

本文深入探讨了三种经典排序算法:插入排序、冒泡排序和快速排序。插入排序适用于少量数据排序,时间复杂度为O(n^2),且为稳定排序方法。冒泡排序通过相邻元素比较与交换实现从小到大排序,其平均时间复杂度也为O(n^2),是一种稳定的排序算法。快速排序在最好情况下具有O(nlogn)的时间复杂度,但最坏情况下退化为O(n^2)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

插入排序:

概念:插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。

最坏时间复杂度:o(0+1+2+...+n-1)=o((n^2-n)/2)=o(n^2);

最好时间复杂度:o(n-1);

平均时间复杂度:o(n^2);

空间复杂度:o(1)。

适用性:插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择。

稳定性:如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。

代码:

void InsertSort(int arr[],int first,int last)
{
	int i,j;
	int temp;
	for(i=first+1;i<=last;i++)
	{
		temp=arr[i];
		j=i-1;
		//与已排序的数逐一比较,大于temp时,该数移后
		while((j>=0)&&(arr[j]>temp))
		{
			arr[j+1]=arr[j];
			j--;
		}
		//存在大于temp的数
		if(j!=i-1)
		{
			arr[j+1]=temp;
		}
	} 
}

冒泡排序:

概念:它重复地走访过要排序的数列,一次比较相邻的两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的尾端,故名冒泡。
冒泡排序算法的运作如下:(从后往前)
(1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。
(2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
(3)针对所有的元素重复以上的步骤,除了最后一个。
(4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

最好时间复杂度:比较n-1次,o(n),交换0次,赋值0次;

最坏时间复杂度:比较1+2+....+n-1=n(n-1)/2次,o(n^2);交换:每次比较都要交换,n(n-1)/2次,o(n^2);赋值:3*交换=o(n^2)。

平均时间复杂度:o(n^2)

算法稳定性

冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变, 所以冒泡排序是一种稳定排序算法。
代码:

void BubbleSort(int a[],int n)//n为数组a的元素个数
{
    int count=0,temp;
    for(int i=0;i<n-1;i++){
        for(int j=0;j<n-1-i;j++){
            if(a[j]>a[j+1])//数组元素大小按升序排列
            {
                temp=a[j];
                a[j]=a[j+1];
                a[j+1]=temp;
				++count;
            }
        }
		if(count==0)
			return;
		else
			count=0;
	}
}

快速排序:

最好:时间复杂度o(nlogn),空间复杂度o(logn);
           最好的情况是每次都正好一分为二,这样一共有log(n)次划分,每次划分都进行n次比较,所以时间复杂度为o(nlogn);每次划分都进行一次(一次有三个函数的调用)递            归调用,所以要花费o(log(n))的递归调用栈。
最坏:时间复杂度o(n^2),空间复杂度o(n);
           最坏的情况是数组本来就有序,这样就退化成了冒泡排序,所以时间复杂度为o(n^2);因为要进行n次递归调用,所以要花费o(n)的递归调用栈。
平均:时间复杂度o(nlogn),空间复杂度o(logn)。
快排分为两步:(1)划分;(2)递归
代码:
void QuickSort(int arr[], int start, int end,int n){
	if(start==end)
		return;
	int k=Partition(arr,start, end, n);
	if(k>start)
		QuickSort(arr,start,k-1,n);
	if(k<end)
		QuickSort(arr,k+1,end,n);
}

int Partition(int arr[],int start,int end,int n){
	if(arr==NULL||start<0||end>=n||n<=0)
		throw std::exception("Invalid Parameter");
	int j=start;
	for(int i=start;i<end;i++){
		if(arr[i]<=arr[end]){
			if(i!=j)
				swap(&arr[j],&arr[i]);
			j++;
		}
	}
	swap(&arr[j],&arr[end]);
	return j;
}


void swap(int* a,int* b){
	int temp=*a;
	*a=*b;
	*b=temp;
}
划分函数Partition的的应用:
(1)快排;
(2)在数组中查找第k大的数;
(3)数组中出现次数超过一半的数字;
(4)数组中最小的k个数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值