萌新笔记之交换排序

1.冒泡排序

听名字还挺可爱的,冒泡(●’◡’●)。
为啥叫冒泡呢?

算法原理是:

对N个元素进行排序,进行N-1次循环。
在对第K次循环中,对前N-K个元素从前往后进行比较,每次比较相邻的两个元素,若前一个元素大于后一个元素,就交换,否则保持位置不变(就是实现了把前N-K个中最大放到了最后)。
所以每次排序一定能保证当前第k大的回落到第N-K个位置,称为第K趟的冒泡。
代码:

void BubbleSort(int a[],int n)
{
    int i,j,temp;
    bool flag;      //相对来说能减少一定的时间复杂度 
    for(i=n-1;i>=0;i--) //为什么这么写呢?其实很简单啊,我每次是排最大,那么当然是从大排到小。 
    {
        flag=false;
        for(j=0;j<i;j++)    //每次是找最大的往后跑。 
        {
            if(a[j]>a[j+1])
            {
                temp=a[j];
                a[j]=a[j+1];
                a[j+1]=temp;
            }
            flag=true;  //如果有交换就标记 
        }
        if(!flag) break;
    }
} 

2.快速排序

快速排序的原理:

将未排序元素根据基准分为两个子序列,其中一个子序列的记录均大于基准,而另一个子序列均小于基准,然后递归的对两个子序列用类似的方法进行排序。
本质上,快速排序使用的是分治法,将问题的规模减小一半左右,然后再分别进行处理。(看不懂没关系,看下面的流程)

快速排序的流程:

对于一趟基准调整的过程:
①:选择一个基准,并与最后一个元素进行交换;
②:设置两个指针Low和High,初值(这个“初值”讲的很妙啊,指针嘛,存的是地址啊)分别指向第一倒数第二个元素
③:重要: 先Low从左往右(顺序)扫描,如果遇到比基准(此时在数组最后位置)大,Stop;High指向的位置开始从右往左(倒序),如果遇到比基准小,Stop;
④:这是第③步结果的执行:1.如果High和Low没有错位(High>Low),High和Low指向的元素互换位置;
⑤:重复③④两步,直到High和Low错位,然后基准和数组元素A[Low]交换。
可以看到,Low和High执行过程中,Low位置之前的元素一定比基准小,High位置之后的元素一定比基准大,这样就完成了一次划分,分成了小于和大于基准的两个子序列。
⑥:递归地对两个子序列用同样的方法进行快速排序算法流程。
感觉是可以随便拿几个数模拟一下一趟快速排序,快速排序算法也达到了分而治之的算法目的。
代码:

void Swap(int *a,int *b)
{
    int temp=*a;
    *a=*b;
    *b=temp;    
}

void QSort(int a[], int Low, int High)//对Low到High区间内进行一趟快速排序 
{
    int Pivot = a[Low]; //随便挑了首元素作为基准; 
    int left=Low,right=High;

    if(Low>=High) return;
    Swap(&a[Low],&a[High]);

    while(1)
    {
        while((Low<High)&&(Pivot>=a[Low])) Low++;
        while((Low<High)&&(Pivot<=a[High])) High--;
        if(Low<High)
            Swap(&a[Low],&a[High]);
        else
            break;
    }
    Swap(&a[Low],&a[right]);//把基准放到正确的位置。

    //递归对两个子序列进行快速排序 
    QSort(a,left,Low-1);
    QSort(a,Low+1,right);
}

void QuickSort(int a[], int n)
{
    QSort(a,0,n-1);
}

快速排序算法的考点Just for the qimo(final) test(还是exam):

时间复杂度:最好的情况下,每次划分都划分成两个基本等长的序列,那么递归层次(即深度)是O(logN),每一次递归层次上的比较总次数都是O(N),所以最好时间复杂度是O(NlogN)。但是如果每次划分都是1和N-1,则快速排序的执行时间就会接近于冒泡排序,可能导致O(N^2)的时间效率。
基准:在A[Low],A[High],A[(Low+High)/2]三个的中值作为基准,这样有可能避免时间复杂度出现的最坏情况。
快速排序是不稳定的。

归并排序

前言:

归并排序是建立在归并操作上的一种排序方法。
归并操作是将两个已经排列好的序列合并成一个有序序列的过程。

归并排序算法的原理:

把长度为N的序列看成N个长度为1的字序列,接下来就是把相邻两个字序列合并,形成[N/2]个长度为2的有序字序列;然后继续合并两两归并,如此一直下去直到剩下一个长度为N的序列。
原理非常简单易懂,直接进行代码实现吧。

归并排序到代码:

void Merge(int a[],int temp[],int Left,int Mid,int Right)
{
    int tp,dis,i,Leftend;
    Leftend=Mid-1;  //左边序列终止位置
    dis=Right-Left+1;//dis为间距 
    tp=Left;        //有序序列的起始位置
    while(Left<=Leftend&&Mid<=Right)
        if(a[Left]<=a[Mid]) temp[tp++]=a[Left++];
        else temp[tp++]=a[Mid++];
    while(Left<=Leftend) temp[tp++]=a[Left++];//如果左边还有多
    while(Mid<=Right) temp[tp++]=a[Mid++];//如果右边还有多
    for(int i=0;i<dis;i++,Right--)
        a[Right]=temp[Right];       //赋值 
}

void MSort(int a[],int temp[],int Left,int Right)
{
    if(Left<Right)
    {
        MSort(a,temp,Left,(Left+Right)/2);
        MSort(a,temp,(Left+Right)/2+1,Right);
        Merge(a,temp,Left,(Left+Right)/2+1,Right);
    }
}

void MergeSort(int a[],int n)
{
    int temp[110];
    MSort(a,temp,1,n);  
}

考点just for the final test:

时间复杂度:进行O(logn)次递归,每次递归有n次比较,所以是O(nlogn)的;
空间复杂度:O(N);
稳定的排序算法。

posted @ 2017-01-11 22:23  see_you_later  阅读(173)  评论(0编辑  收藏  举报