基本思想:
在要排序的一组数中,对当前未排序好的范围全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的数往上冒,俗称冒泡。
总结:每当两相邻的数比较后发现他们的排序与排序要求相反时,就将他们互换。嵌套排序完成整个冒泡过程
算法的实现:
1、每次排序把最大的数排在最后一个;
2、然后下次排序可以少计算一次,因此是j-i;
3、j
void BubbleSort(int a[],int n)
{
for(int i=0;i1;i++)
{
for(int j=0;j1;j++)//重要,每一轮把最大数排到最后
{
if(a[j]>a[j+1])
{
int tmp=a[j+1];
a[j+1]=a[j];
a[j]=tmp;
}
}
}
}
冒泡排序算法的改进
改进方法:
加入一个标志变量exchange,用于标志某一趟排序过程中是否有数据交换,如果进行某一趟排序时并没有进行数据交换,则说明数据已经按要求排列好,可立即结束排序,避免不必要的比较过程,减少时间损耗。(比如:有时排序到中间的步骤时,就全部排序完成,后面的排序过程是可以省略的,因此可以关闭开关)
改进的地方:
1、普通的冒泡算法是大的一致下沉,本次改进为小的一致上升;
2、加入一个标志位,用于判断是否需要进行后续排列;
代码如下:
void BubbleSorter( int a[],int n)
{
int flag=1;
for(int i=0;i1;i++)
{
for(int j=n-1;j>i;j--)
{
int flag=0;
if(a[j]1])
{
int tmp=a[j];
a[j]=a[j-1];
a[j-1]=tmp;
flag=1;
}
}
}
}
最好情况:若原数组本身就是有序的,仅需要n-1次比较就可以完成,时间复杂度为O(n);
一般情况:比较次数为:n-1+n-2+….+1=n(n-1)/2=O(n^2),因此时间复杂度依然为O(N^2);
快速排序是在实践中最快的已知排序算法,它的平均运行时间是O(NlogN)。
基本思想:
1)选择一个基准元素,通常选择第一个元素或者最后一个元素
2)通过一趟排序将待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小。另一部分记录的元素值均比基准的值大;
3)此时基准元素在其排好序后的正确位置;
4)然后分别对两部分序列用相同的方法继续进行排序,直到整个序列有序。
代码实现分析:
快速排序主要是由这几部完成的:1、通过一次快速排序完成中间位置的确定;2、通过迭代完成左右两测序列的排序,使用方式同第一步一样;
实现起来,伪代码如下:
void QuickSort(int a[],int p, int r,int n)
{
if(pint q=Partiton(a,p,r);
QuickSort(a,p,q-1,n);
QuickSort(a,q+1,r,n);
}
return ;
}
数组的排序方式
这个是快速排序的重点内容,也是算法的核心内容。
核心算法可以简述为以下几步:
1、选取一个参考位,一般是第一个或最后一个,记为r。确定数组的开始位置,记为q;
2、快速排序是通过两个指针的移动完成的。由于本题是数组,给定下标为i, j。 i是给定数组起始位置的前一个位置,j是起始位置;(以上都是用到工具的初始化)
3、比较过程是由一个循环和一个判断完成的。循环过程中,j每次向前移动一个位置,表示循环位置;再判断当前位置a[j]
#include
using namespace std;
int Partiton(int a[],int p,int r )
{
int i,j;
i=p-1;
j=p;
while(jif(a[j]//位置很关键
int tmp=a[j];
a[j]=a[i];
a[i]=tmp;
}
(j)++;
}
//对最后一个数进行交换
i++;
int tmp=a[r];
a[r]=a[i];
a[i]=tmp;
return i;
}
void print(int a[], int n);
int count1=1;
void QuickSort(int a[],int p, int r,int n)
{
if(pint q=Partiton(a,p,r);
printf("第%d次快速排序:",count1);
print(a,n);
count1++;
QuickSort(a,p,q-1,n);
QuickSort(a,q+1,r,n);
}
return ;
}
void print(int a[], int n)
{
for(int j=0;jcout<" ";
}
cout<int main()
{
int a[]={2,8,7,1,3,5,6,4};
int n=8;
int p=0;
int r=n-1;
QuickSort(a,p,r,n);
/*int length;
int* A;
while(1)
{
cout<<"请输入数组的长度"<>length;
if(length>0)
{
cout<<"请输入数组中的元素"<>A[i];
}
QuickSort(A,0,length-1);
print(A,length);
}
}*/
system("pause");
return 0;
}
输入结果如下:
快速排序涉及到递归调用,所以该算法的时间复杂度还需要从递归算法的复杂度开始分析:
递归算法的时间复杂度为:T[n]=aT[n/b]+f(n);
最优情况下的时间复杂度
快速排序最优的情况就是每一次取到的元素(取的参考值)都刚好平分整个数组;
此时的时间复杂度公式为:T[n]=2T[n/b]+f(n);其中2T[n/b]为平分后的子数组的时间复杂度;f(n)是解决这次平分数组所花费的时间;
计算得:
T[n] = 2^(logn) T[1] + nlogn = n T[1] + nlogn = n + nlogn ;其中n为元素个数;
又因为当n >= 2时:nlogn >= n (也就是logn > 1),所以取后面的 nlogn;
综上所述:快速排序最优的情况下时间复杂度为:O( nlogn )
最差情况下时间复杂度:
最差的情况就是每一次取到的元素就是数组中最大/最小的,这种情况其实就是冒泡排序。也就是每一次排好一个元素。
综上所述:快速排序最差的情况下时间复杂度为:O(n^2)
平均时间复杂度
快速排序的平均时间复杂度是:O(nlogn)
由于快速排序的最坏情况是:取的参考值就是最大值或者最小值,这种情况的快速排序算法复杂度最高,和冒泡排序类似。
改进方法:
每次排序前取三个位置的数进行比较,分别是起始位置,终点位置和中间位置。对着三个位置的数的要求是:参考位的取值是取中间数。因此在每次快速排序需要对起始位置,终点位置和中间位置的值进行排序,尽量使得取得参考点是中间大小的值。
伪代码参考如下: