常见排序算法

本文详细介绍了常见的六种排序算法:冒泡排序、选择排序、快速排序、归并排序、堆排序和桶排序。包括它们的工作原理、时间复杂度和空间复杂度,以及排序稳定性。这些排序算法是理解数据结构和算法的基础,对于提升编程能力至关重要。

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

写于2013年8月29号


自己学会常见的这几种算法,并整理成文。

代码实现



名词解释

时间复杂度:算法占用的时间(一般与数据数量呈正相关)。

空间复杂度:算法占用的空间(一般与数据数量呈正相关)。

算法稳定性:是指是否会交换值相等的两个数据的初始位置。


一.冒泡排序 Bubble Sort

冒泡排序(BubbleSort)是一种入门级别的算法,较好理解。一般作为第一种算法被认识。

 

冒泡排序是一种稳定的排序。

平均时间按复杂度O(n*n)   【最好时间复杂度O(n),最坏时间复杂度O(n*n)】

空间复杂度O(1)

 

算法的运作如下:

1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。

2、对每一对相邻元素重复步骤1,从开始第一对到结尾的最后一对。每趟过后,排在最后的元素最大。

3、重复步骤2,直到剩下一个元素。

代码:

代码:
1	for(int i=0;i<n-1;i++)  		//n-1趟排序
2	    {  
3	        for(int j=n-1;j>i;j--)	//j>i因为i前面的元素已经排好了  
4	        {  
5	            int temp=0;  
6	            if(arrayA[j]<arrayA[j-1])  //比较相邻的两个元素,见步骤1
7	            {  
8	                temp=arrayA[j];  
9	                arrayA[j]=arrayA[j-1];  
10	                arrayA[j-1]=temp;  
11	            }  

二、选择排序Selection Sort

选择排序其实是冒泡的升级,每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。

 

冒泡排序是一种稳定的排序。

平均时间按复杂度O(n*n)   【最好最坏均是O(n*n)】

空间复杂度O(1)

 

算法运作如下:

1、比较所有待排序元素。找到最小(最大)的元素。

2、将这个元素放入已排序数列的最后。

3、持续每次对待排序元素重复上面的步骤,直到没有待排序元素。

 

代码:
1	for(int i=0;i<n-1;i++)  	//n-1趟排序,因为最后只剩一个元素的时候不用再比较
2	    {  
3	        int index=i;  	//索引值,记录当前已排序数列排列到的位置
4	        for(int j=i+1;j<n;j++)	//j从i+1开始,因为前面的元素已经排好了  
5	        {  
6	            if(arrayA[j]<arrayA[index])  
7	                index=j;		//每趟将待排序数据中的最小值的位置存放到index
8	        }  
9	  
10	//若该趟index指向的的最小值不在i处(最前面),则交换array[index]和array[i]的值
11	        if (index!=i)          
12	        {  
13	            //交换数据
14	            int temp = arrayA[i];  
15	            arrayA[i] = arrayA[index];  
16	            arrayA[index] = temp;  
17	        }  
18	    }  

三、快速排序QuickSort

快速排序是对冒泡排序的一种改进。

 

快速排序是一种不稳定的排序。

平均时间按复杂度O(nlogn) 【最好时间复杂度O(nlogn),最坏时间复杂度O(n*n)】

空间复杂度O(nlogn)

 

算法运作如下:

1、以第一个元素作为key

2、对数组进行分区,使key左边元素的值都不大于key,右边的元素值都不小于key,最后将作为key的元素调整到排序后的正确位置。

3、将步骤2结束后的数列二分为key的左右两部分,递归快速排序,最终二分到只有一个元素,排序完成。

 

步骤2简图


全过程简图:

初始状态   4938659776132749
    步骤二:     2738134976976549
    步骤三:    13273849657697
    有序序列: 1327384949657697

 

#include<stdio.h>  
#include<stdlib.h>  
#define len 8  
  
  
int Partition( int d[],int low,int high)  
{    
   int t;  
   t = d[low];  
   while(low<high)  
   {  
      while(low<high && d[high]>=t )  --high;  
      d[low] = d[high];  
      while( low<high && d[low]<=t )  ++low;  
      d[high] = d[low];  
    }  
     
   d[low] = t;  
   return low;  
   // for(int k=0;k<len;k++)  
    // printf("%d\n",d[k]);  
}  
  
void QSort(int *d,int low,int high)  
{ //对顺序表中的子序列作快速排序  
    int pivotloc;  
    if( low <high )  
    {  
        pivotloc = Partition(d,low,high);  
        QSort(d,low,pivotloc-1);  
        QSort(d,pivotloc+1,high);  
    }  
}  
  
void QuickSort(int *d)  
{  
  QSort(d,0,len-1);  
}  
  
  
  
  
  
int main()  
{    
    int d[len] = {49,38,65,97,76,13,27,49};  
      
    QuickSort(d);  
    for(int k=0;k<len;k++)  
     printf("%d\n",d[k]);  
    return 0;  
}  


参考:http://blog.youkuaiyun.com/lvyuan30276/article/details/9813705



四、归并排序Merge Sort

“归并”的含义是将两个或两个以上的有序表组合成一个新的有序表。

速度仅次于快速排序(数量级相等,系数不同)。

一般用于对总体无序,但是各子项相对有序的数列。

 

归并排序是一种稳定的排序。

平均时间按复杂度O(nlogn) 【最好时间复杂度O(nlogn),最坏时间复杂度O(nlogn)】

空间复杂度O(n)

 

算法原理:

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

第二步:设定两个指针,指向两个有序表的头

第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

第四步:重复步骤三直到某一指针达到序列尾,将另一序列剩下的所有元素直接复制到合并序列尾。

第五步:将第四步重复,直到完成整个数列。

 

原理简图



代码:
1.	#include <iostream>  
2.	using namespace std;  
3.	  
4.	const int maxSize = 100;  
5.	  
6.	/* 
7.	函数名:    Merge 
8.	函数功能:   将有序的SR[begin, middle]和SR[middle+1, end]排序后存储到TR中。 
9.	函数参数:   int SR  原数组 
10.	            int TR  目标数组 
11.	*/  
12.	void Merge(int SR[], int TR[], int begin, int middle, int end)  
13.	{  
14.	    int i, j, k;  
15.	    i = begin;  
16.	    j = middle + 1;  
17.	    k = begin;  
18.	    while (i <= middle && j <= end)  
19.	    {  
20.	        if (SR[i] <= SR[j])  
21.	        {  
22.	            TR[k] = SR[i];  
23.	            k++;  
24.	            i++;  
25.	        }  
26.	        else  
27.	        {  
28.	            TR[k] = SR[j];  
29.	            k++;  
30.	            j++;  
31.	        }  
32.	    }  
33.	  
34.	    while (i <= middle)  
35.	    {  
36.	        TR[k] = SR[i];  
37.	        k++;  
38.	        i++;  
39.	    }  
40.	  
41.	    while (j <= end)  
42.	    {  
43.	        TR[k] = SR[j];  
44.	        k++;  
45.	        j++;  
46.	    }  
47.	}  
48.	  
49.	void MergeSort(int SR[], int TR1[], int begin, int end)  
50.	{  
51.	    if (begin == end)  
52.	    {  
53.	        TR1[begin] = SR[begin];  
54.	    }  
55.	    else  
56.	    {  
57.	        int TR2[maxSize + 1];  
58.	        int middle = begin + (end - begin) / 2;     /* 将SR[begin,end]平均分成SR[begin, middle]和SR[middle+1, t] */  
59.	        MergeSort(SR, TR2, begin, middle);          /* 递归地将SR[begin, middle]归并为有序的TR2[begin, middle] */  
60.	        MergeSort(SR, TR2, middle+1, end);          /* 递归地将SR[middle+1, end]归并为有序的TR2[middle+1, end] */  
61.	        Merge(TR2, TR1, begin, middle, end);        /* 将TR2[begin, middle]和TR2[middle+1, end]归并到TR2[begin,end] */  
62.	    }  
63.	}  
64.	  
65.	int main()  
66.	{  
67.	    int array[] = {50, 10, 90, 30, 70, 40, 80, 60, 20};  
68.	    MergeSort(array, array, 0, 8);  
69.	    for (int i = 0; i < 9; i++)  
70.	    {  
71.	        cout << array[i] << " " ;  
72.	    }  
73.	    cout << endl;  
74.	}  

参考:

http://blog.youkuaiyun.com/listener51/article/details/9839723       图解

http://blog.youkuaiyun.com/begginghard/article/details/9878433     算法

 

五、堆排序Heap Sort

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

 

背景知识:1991年计算机先驱奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德Robert W.Floyd和威廉姆斯J.Williams在1964年共同发明了著名的堆排序算法Heap Sort

 

时间复杂度为O(n*logn)【最好、最坏、平均三者,在数量级上相等】

空间复杂度O(1)【一个temp单元,用来辅助存储】

堆排序不稳定

 

算法描述:

1、        将原数据(N1,Nn)整理为大根堆

2、        将堆顶元素与排在线性最后的元素交换位置

3、        将数据(N1,Nn-1)重置为大根堆

4、        重复步骤2和步骤3,直到堆中仅剩一个元素

 

代码:
1.	//用大根堆,排序后是从小到大排序(每次将最后一个元素与堆顶元素交换)    
2.	//假设数组data的下标从1开始    
3.	void HeapSort(int data[], int length)    
4.	{    
5.	    int i;    
6.	    for(i=length/2; i>=1; i--)       //建立一个大根堆    
7.	        HeapAdjust(data, i, length);    
8.	    for(i=length; i>1; i--)    
9.	    {    
10.	        Swap(data, 1, i);    //将根节点(此堆中最大元素)与最后一个元素交换位置
11.	        HeapAdjust(data, 1, i-1);  //抛出堆中最后一个位置,重新整理为最大堆  
12.	    }    
13.	}    
14.	    
15.	//data[s+1]¬¬—data[m]已满足堆的性质,现在调整data[s],使得data[s]—data[m]也成为一个大根堆    
16.	void HeapAdjust(int data[], int s, int m)    
17.	{    
18.	    int temp, j;    
19.	    temp = data[s];    
20.	    for(j=2*s; j<=m; j=j*2)    
21.	    {//在data[i]的两个孩子data[2i]和data[2i+1] 中的较大者,跟data[i]进行比较,若孩子的值较大,则交换父节点和此孩子节点,保证其满足大根堆的性质。
22.	        if(j<m && data[j]<data[j+1])   //选择兄弟节点中的较大者
23.	            j++;    
24.	        if(temp >= data[j])   //如果该节点小于父节点,则符合条件,跳出 
25.	            break;    
26.	        data[s] = data[j];    //如果该节点的值大于父节点,进行值的交换
27.	        s = j;    
28.	    }    
29.	    data[s] = temp;    	//此时辅助空间的值重新为父节点
30.	}    


六、桶排序Bin Sort

桶排序特别适合数据随机分布在域上的情况。

其思想就是把区间[min,max]划分成n个相同大小的桶,然后将所有数据放到对应的桶中去(sum放到num/n+1号桶中)。然后对各个桶中的数进行排序(此处算法不做限制),最后按次序把各桶中的元素列出来即可。

 

数据随机分配在域上的情况下,

平均时间复杂度为线性的O(N+C),其中C=N*(logN-logM)【最好时间复杂度为O(N),但极费空间;最坏时间复杂度为子排序算法的复杂度】

空间复杂度为O(B*N),其中B是桶的个数



代码

1.分组
2.使用其他通用排序算法对各个桶内元素排序

代码略



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值