【算法笔记】4.1 三大简单排序

  • 这是《算法笔记》的读书记录
  • 本文参考自4.1节

1. 选择排序

  • 思想:把数组分为有序的前半部分和无序的后半部分,每次从无序的后半部分选出最小的元素交换到分界处,从而使有序部分不断增长,直到完全有序

  • 这个思想可以很方便地转换为递归形式,示例代码如下

    //选择排序,复杂度 O(n^2) 
    #include<iostream>
    using namespace std;
    
    void selectSort(int *a,int n)
    {
          
          
    	//n次操作 
    	for(int i=0;i<n;i++)
    	{
          
          
    		//从后n-i个数中选出最小的,下标为k 
    		int k=i;
    		for(int j=i;j<n;j++)		
    			if(a[j] < a[k])
    				k=j;
    		
    		//交换a[k]和a[i] 
    		int temp = a[i];
    		a[i] = a[k];
    		a[k] = temp;
    	}			
    } 
    
    //对长len的数组a的前n个元素排序 
    void selectSort2(int *a,int n,int len) 
    {
          
          
    	//退出条件:全部n个数都已经排序 
    	if(n >= len+1)
    		return;
    
    	//从后n-i个数中选出最小的,下标为k
    	int k=n-1;
    	for(int i=n;i<len;i++)		
    		if(a[i] < a[k])
    			k=i;
    	
    	//交换a[k]和a[n-1] 
    	int temp = a[k];
    	a[k] = a[n-1];
    	a[n-1] = temp;
    	
    	//递归排序前n+1个数 
    	selectSort2(a,n+1,len);
    }
    
    int main()
    {
          
          
    	int a[15] = {
          
          2,4,1,3,5,7,6,8,10,9,2,2,4,5,1};
    	//selectSort(a,15);		// 标准选择排序
    	selectSort2(a,1,15);	// 递归选择排序
    	
    	for(int i=0;i<15;i++)
    		cout<<a[i]<<" ";
    	cout<<endl;
    	
    	return 0;
    } 
    
  • 复杂度分析:进行n趟操作,每趟选出[i,n)部分中最小的元素交换,时间复杂度 O ( n 2 ) O(n^2) O(n2)

2. 插入排序

  • 思想:类似选择排序,把数组分为有序的前半部分和无序的后半部分,每次把无序后半部分中第一个数移动到有序部分的合适位置,从而使有序部分不断增长,直到完全有序

  • 这个思想也可以很方便地转换为递归形式,示例代码如下

    //插入排序,复杂度 O(n^2) 
    #include<iostream>
    using namespace std;
    
    void insertSort(int *a,int n)
    {
          
          
    	//n-1趟排序 
    	for(int i=1;i<n;i++)
    	{
          
          
    		//把a[i]移到合适的位置 
    		int temp = a[i],j = i;
    		while(j>0 && temp<a[j-1])
    		{
          
          
    			a[j] = a[j-1];
    			j--;
    		}
    		a[j] = temp;
    	}			
    } 
    
    //对长len的数组a的前n个元素排序 
    void insertSort2(int *a,int n,int len)
    {
          
          
    	//退出条件:全部n个数都已经排序 
    	if(n >= len+1)
    		return;
    
    	//把最后一个元素放到合适的位置 
    	int temp = a[n-1],i = n-1;
    	while(i>0 && temp<a[i-1])
    	{
          
          
    		a[i] = a[i-1];
    		i--;
    	}
    	a[i] = temp;		
    	
    	//递归排序前n+1个数 
    	insertSort2(a,n+1,len);
    }
    
    int main()
    {
          
          
    	int a[15] = {
          
          2,4,1,3,5,7,6,8,10,9,2,2,4,5,1};
    	//insertSort(a,15);		// 标准插入排序
    	insertSort2(a,1,15);	// 递归插入排序
    	
    	for(int i=0;i<15;i++)
    		cout<<a[i]<<" ";
    	cout<<endl;
    	
    	return 0;
    } 
    
  • 复杂度分析:进行n-1趟操作(数量级n),每趟至多前i个数(数量级n)找出位置,时间复杂度 O ( n 2 ) O(n^2) O(n2)

3. 冒泡排序

  • 思想:每轮操作从头开始依次比较相邻两个数,如果左边的数大于右边的就交换。第一轮操作中,不管最大数在哪里,都能在操作结束后交换到最右边;同样的,第二轮操作把次大数交换到最右边,循环直到有序。

  • 和前两个排序方法不同,冒泡排序中数组右侧是有序部分;选择/插入排序中数组左侧是有序部分

  • 同样的,这个也能改成递归写法

    //冒泡排序,复杂度 O(n^2) 
    #include<iostream>
    using namespace std;
    
    void bubbleSort(int *a,int n)
    {
          
          
    	//n-1次操作 
    	for(int i=1;i<n;i++)
    	{
          
          
    		//每次从无序部分冒一个数上来 
    		for(int j=0;j<n-i;j++)		
    		{
          
          
    			if(a[j] > a[j+1])
    			{
          
          
    				//交换a[j]和a[j+1] 
    				int temp = a[j];
    				a[j] = a[j+1];
    				a[j+1] = temp;
    			}
    		}
    	}			
    } 
    
    //从长len的数组a的前len-n个元素(无序部分)中,把最大的数浮上来 
    void bubbleSort2(int *a,int n,int len)
    {
          
          
    	if(n>=len)
    		return;
    	
    	//每次从无序部分冒一个数上来 
    	for(int j=0;j<len-n;j++)		
    	{
          
          
    		if(a[j] > a[j+1])
    		{
          
          
    			//交换a[j]和a[j+1] 
    			int temp = a[j];
    			a[j] = a[j+1];
    			a[j+1] = temp;
    		}
    	}
    	
    	//递归排序,把次大的数浮动上来 
    	bubbleSort2(a,n+1,len);
    } 
    
    
    int main()
    {
          
          
    	int a[15] = {
          
          2,4,1,3,5,7,6,8,10,9,2,2,4,5,1};
    	//bubbleSort(a,15);
    	bubbleSort2(a,1,15);
    	
    	for(int i=0;i<15;i++)
    		cout<<a[i]<<" ";
    	cout<<endl;
    	
    	return 0;
    } 
    
  • 复杂度分析:也是两个数量级为n的二重循环,时间复杂度 O ( n 2 ) O(n^2) O(n2)

4. 小结

  • 这里介绍了三种简单排序算法,时间复杂度都是 O ( n 2 ) O(n^2) O(n2)

  • 每轮操作的有序部分

    • 选择/插入排序:在前
    • 冒泡排序:在后
  • 递归公式:对n个数进行排序 = 把第n个数插入有序部分 + 对n-1个数进行排序

猜你喜欢

转载自blog.csdn.net/wxc971231/article/details/108430196
今日推荐