算法(第四版)学习笔记(二)——初级排序算法

时间:2022-02-13 10:45:53

 


时间复杂度(Time Complexity):

总运算次数表达式中受n的变化影响最大的那一项(不含系数)(注:若算法中语句执行次数为一个常数,则时间复杂度为O(1))
若T(n)/f(n)求极限可得到一常数c,则时间复杂度T(n)=O(f(n))。
  • 一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)
  • 算法的基本操作重复执行的次数是模块n的某一个函数f(n)
随着模块n的增大,算法执行的时间的增长率和f(n)的增长率成正比,所以f(n)越小,算法的时间复杂度越低,算法的效率越高。

空间复杂度(Space Complexity):

一个算法在运行过程中临时占用存储空间大小的量度(包括程序代码所占用的空间输入数据所占用的空间辅助变量所占用的空间这三个方面。)
注:
  • 如当一个算法的空间复杂度为一个常量,即不随被处理数据量n的大小而改变时,可表示为O(1);
  • 当一个算法的空间复杂度与以2为底的n的对数成正比时,可表示为0(log2n);
  • 当一个算法的空I司复杂度与n成线性比例关系时,可表示为0(n).

 

冒泡排序

 

 

选择排序

步骤:(升序)

   首先找到数组中最小的数,与数组第一位数交换位置(如果最小数是本身与本身交换)。接着在剩下的数中找第二小的数,与数组第二位数交换位置(如果第二小数是本身与本身交换)........按照相同步骤依次执行最后一个元素。

 

数据交换N次,数据比较(N-1)+(N-2)+........+3+2+1=N*(1+N-1)/2=N^2/2次(最后一个元素与自身交换)

时间复杂度:O(n2)

空间复杂度:O(1)

 1 #include<stdio.h>
2 #include<malloc.h>
3 int main()
4 {
5 int n,i,j,min,temp;
6 scanf("%d",&n);
7 int *a=(int *)malloc(sizeof(int)*n);
8 for(i=0;i<n;i++)
9 scanf("%d",&a[i]);
10 for(i=0;i<n;i++)
11 {
12 min=a[i];//最小数
13 temp=i;//最小数在数组中的位置
14 for(j=i+1;j<n;j++)
15 {
16 if(min>a[j])//比较大小
17 {
18 min=a[j];
19 temp=j;
20 }
21 }
22 a[temp]=a[i];//交换
23 a[i]=min;
24 }
25 for(i=0;i<n;i++)
26 printf("%d ",a[i]);
27 return 0;
28 }
  • 运行时间与输入无关,有序数组输入其排序用时和相同长度的无序数组是一样的。
  • 数据移动最少,每次只需移动两个数组

插入排序

直接插入排序 

步骤:(升序)

 将原数组分成两组,一组为已排好序的数组A,另一组为乱序数组B。数组A倒序(A[length-1])每个元素依次与数组B的一个元素比较(从B[0]开始),若A组某元素比B组元素大,A组元素后退一位为,B组元素腾出空间,然后B组推下一个元素.

时间复杂度:O(n2)

空间复杂度:O(1)

 1 #include<stdio.h>
2 #include<malloc.h>
3 void sort(int *a,int n);
4 int main()
5 {
6 int n,i;
7 scanf("%d",&n);
8 int *a=(int *)malloc(sizeof(int )*n);
9 for(i=0;i<n;i++)
10 scanf("%d",&a[i]);
11 sort(a,n);
12 for(i=1;i<n;i++)
13 printf("%d ",a[i]);
15 return 0;
16 }
17 int less(int a,int b)
18 {
19 if(a<b) return 1;
20 return 0;
21 }
22 void sort(int *a,int n)
23 {
24 int i,j,temp,k;
25 for(i=1;i<n;i++)
26 {
27 temp=a[i];
28 for(j=i-1;j>=0&&less(temp,a[j]);j--)
29 {
30 a[j+1]=a[j];
31 }
32 a[j+1]=temp;
33 }
34 }

 算法(第四版)学习笔记(二)——初级排序算法

  • 插入排序所需时间取决于输入元素的顺序
  • 插入排序更适用于部分有序的数组,和小规模数组

希尔排序

 步骤:(升序)

为加快速度的插入排序,交换不相邻的元素将数组部分变有序。使数组间隔h(h会改变)个元素有序。h在变化前,程序使h个元素间隔的小数组有序。

  例:2—6—70(小数组每个元素间隔h个元素)..

时间复杂度:

空间复杂度:O(1)

#include<stdio.h>
#include
<malloc.h>
//伸序
int less(int a[],int i,int j)
{
if(a[i]<a[j])
return 1;
return 0;
}
int main()
{
int n,h,i,j,temp,k;
scanf(
"%d",&n);
int *a=(int *)malloc(sizeof(int)*n);
for(i=0;i<n;i++)
scanf(
"%d",&a[i]);
h
=1;
while(h<n/3)
h
=3*h+1;
while(h>=1)
{
for(i=h;i<n;i++)
{
for(j=i;j>=h&&less(a,j,j-h);j-=h)
{
temp
=a[j];
a[j]
=a[j-h];
a[j
-h]=temp;
}
}
h
/=3;
}
for(i=0;i<n;i++)
printf(
"%d ",a[i]);
return 0;
}

 疑问1:出现6—4—5这样的小数组,排序后还是为无序小数组?

       答:并不会出现6—4—5这样的小数组,因为:

    j=h 为 6—4小数组,会重新排序为有序4—6小数组

    j=2h  为4—6—5小数组,会重新排序为有序4—5—6小数组

疑问2:如何选择h的递增数列?

    书中用的的3*h+1与复杂递增序列的性能相近,但比较简单,所以书中将该递增数列提出作为参考 

    并未找到最优递增数列   

优势:

   希尔排序比插入排序和选择排序快得多,并且数组越大,优势越大。 

 

参考资料:《算法第四版》   

如何计算时间/空间复杂度:http://www.cnblogs.com/zakers/archive/2015/09/14/4808821.html