1. 程式人生 > >演算法小結--快速排序+歸併排序

演算法小結--快速排序+歸併排序

快速排序和歸併排序都是採用分治的思想,將一個無序序列不斷細分,然後慢慢組合成有序序列。

快速排序:它的基本思想是:根據基準通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所有資料都要小,然後再按此方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。

粗體為劃分基準 key=4
序號 1 2 3 4 5 6 7 8
輸入 4 2 8 7 1 3 5 6
從頭部開始找比key大的數,找到後停留i=3,再從尾部開始找比key小的數j=6,找到後交換兩個值,以此方式,知道i>=j 退出。
一次劃分:2 3 1 4

7 8 5 6
然後 將 2 3 1 和 7 8 5 6 按第一次的方式劃分
直至完成。

程式碼實現:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define n 5
//#define RAND_MAX
int a[n]={2,6,4,3,1};

void Swap(int i,int j)
{
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}


int Partition(int p,int r)
{
    int
i = p,j=r+1; int x = a[p]; while(1) { while(a[++i]<x&&i<r); //從左到右,直到找到比x大的,或者i<r while(a[--j]>x); //從右到左,直到找到比x小的 if(i>=j) break; Swap(i,j); } a[p] = a[j]; //將基準插入對應位置 a[j] = x; return j; } /* int RandomPartition(int p,int r) { int t =(int) (n*rand()/RAND_MAX); //產生0到n的整數 Swap(t,p); return Partition(p,r); } */
void QuickSort(int p,int r) { int q; if(p<r) { q = Partition(p,r); //q = RandomPartition(p,r); //啟用基準元素隨機化 QuickSort(p,q-1); QuickSort(q+1,r); } } int main() { int i; QuickSort(0,n-1); for(i=0;i<n;i++) { printf("%d ",a[i]); } return 0; }

快速排序一般情況都是以第一個元素作為key進行劃分,這樣容易出現太大的偶然性。如果key值差不多是這個有序序列的中間值,那麼排序效率比較高,如果不能將序列劃分成等同的兩塊,那麼效率會降低。

改進方法,在序列中隨機抽取key值,降低偶然性。
實現如下:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define n 5
//#define RAND_MAX
int a[n]={2,6,4,3,1};

void Swap(int i,int j)
{
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}


int Partition(int p,int r)
{
    int i = p,j=r+1;
    int x = a[p];
    while(1)
    {
        while(a[++i]<x&&i<r);  //從左到右,直到找到比x大的,或者i<r
        while(a[--j]>x);       //從右到左,直到找到比x小的
        if(i>=j) break;
        Swap(i,j);
    }
    a[p] = a[j]; //將基準插入對應位置
    a[j] = x;
    return j;
}


int RandomPartition(int p,int r)
{
    int t =(int) (p+(r-p)*rand()/RAND_MAX); //產生p到r的整數
    Swap(t,p);
    return Partition(p,r);

}


void QuickSort(int p,int r)
{
    int q;
    if(p<r)
    {
        //q = Partition(p,r);
        q = RandomPartition(p,r); //啟用基準元素隨機化
        QuickSort(p,q-1);
        QuickSort(q+1,r);
    }
}

int main()
{
    int i;
    QuickSort(0,n-1);
    for(i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    return 0;
}

歸併排序:

合併排序法是將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然後再把有序子序列合併為整體有序序列。

這裡寫圖片描述

程式碼如下:

#include <stdio.h>
#include <stdlib.h>
#define n 6
int a[n]={7,2,9,4,7,1};
int b[n]={0};

void Copy(int l,int r)
{
    int i;
    for(i=l;i<=r;i++)
    {
        a[i]=b[i];
    }
}

void Merge(int l,int m,int r)
{
    //合併c[l,m]和c[m+1,r] 到d[l,r]
    int i =l,j = m+1,k = l;
    while( (i<=m) && (j<=r))
    {
        if( a[i]<=a[j] ) b[k++]=a[i++];
        else b[k++] = a[j++];
    }

    int q;
    if(i>m)
    {
        for(q=j;q<=r;q++)
        b[k++]=a[q];

    }else
    {
        for(q=i;q<=m;q++)
        b[k++]=a[q];
    }


    int s;
    for(s=l;s<=r;s++)
    {
        //printf("%d \n",b[s]);
        a[s]=b[s];
    }
}

void MergeSort(int left,int right)
{
    if(left < right)
    {
        int i = (left+right)/2;
        MergeSort(left,i);
        MergeSort(i+1,right);
        Merge(left,i,right); //合併到陣列b
        //Copy(left,right); //複製到陣列a
    }
}

int main()
{
    MergeSort(0,n-1);
    int i;
    for(i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}

相關推薦

演算法小結--快速排序+歸併排序

快速排序和歸併排序都是採用分治的思想,將一個無序序列不斷細分,然後慢慢組合成有序序列。 快速排序:它的基本思想是:根據基準通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所有資料都要小,然後再按此方法對這兩部分資料分別進

經典排序演算法的實現(選擇,插入,shell,堆,快速歸併排序

1.選擇排序 //選擇排序 void selectSort(int * arr, int n) { for (int i = 0; i < n - 1; i++) { int min = arr[i]; int minPos = i; for (int j = i

常見比較排序演算法的實現(歸併排序快速排序、堆排序、選擇排序、插入排序、希爾排序

這篇部落格主要實現一些常見的排序演算法。例如: //氣泡排序 //選擇排序 //簡單插入排序 //折半插入排序 //希爾排序 //歸併排序 //雙向的快速排序(以及快速排序的非遞迴版本) //單向的快速排序 //堆排序 對於各個演算法的實現

常用演算法--基本排序演算法(氣泡排序,選擇排序,插入排序,快速排序,歸併排序,桶排序)

1.氣泡排序: 思想:以小到大排序為例,對無序的資料兩兩進行比較,大的放在右面,小的放在左面. (1,2),(1,3)...(2,3),(2,4)...(n-1,n-1),(n-1,n) 時間複雜度: O(n) ~ O(n2)O(n2~ Java程式碼實現: p

排序演算法: 氣泡排序快速排序,希爾排序,直接插入排序 ,直接選擇排序,歸併排序,堆排序

幾種排序演算法分析:   氣泡排序:   氣泡排序的方法排序速度比較慢。   思路:進行n-1排序,第一次排序先找出最小的數字,放在第一個位置,然後在剩餘的數字中再找出最小的數字,放在第二個位置上,依次類推,可以排出所有的數字。   當然也可以從大到小的排序。   例如

【C++實現】基本排序演算法 插入排序——歸併排序——快速排序——堆排序

/* 排序總結:(基於100w隨機數,有序數、重複數測試) 1、插入排序適合近乎有序的序列 2、歸併排序優化:(優化前       120S) 1)資料小於15時採用插入排序 10S 2)避免頻繁動態申請記憶體 memcpy(dest,src,sizeof(int)*len)

Java-時間複雜度為O(nlogn)的排序演算法(快速排序, 歸併排序, 堆排序, 希爾排序)

/** 包含多種靜態排序方法 * Created by Andre on 2016/6/27. */ public class Sorter { /** * 快速排序 * 遞迴形式 * 第一個記錄為樞軸 * 不穩定

其他排序演算法快速歸併、堆排序(top N)

快速排序 快速排序是一種分治排序演算法,採用了遞迴的方法。 原理: 1.先從數列中取出一個數作為基準數。 2.分割槽過程:將比這個數大的數全放到它的右邊,小於或等於它的數全放到它的左邊。 3.對左右區間重複第二步,直到各區間只有一個數

從零開始學演算法(四)歸併排序

從零開始學演算法(四)歸併排序 歸併排序 演算法介紹 演算法原理 演算法簡單記憶說明 演算法複雜度和穩定性 程式碼實現 歸併排序 程式碼是Javascript語言寫的(幾乎是虛擬碼) 演算

演算法第五記-歸併排序

      今天我要講的排序演算法是歸併排序,首先我想提出一個問題(很多演算法題的思路都源於此),給定兩個已排序的序列,如何將其兩個序列合併為一個大序列並且依然保持有序。思路很簡單每個小序列維持一個指標指向左邊界,然後兩個序列的左邊界進行比較大小,小的那方加入新的序列中

單鏈表的排序(關鍵詞:連結串列/單鏈表/排序/快速排序/歸併排序

https://leetcode.com/problems/sort-list/ https://leetcode.com/problems/sort-list/discuss/46807/Quick-sort-Merge-sort-Python https://leetcode.com

java排序演算法(四)------歸併排序

歸併排序: 是利用歸併的思想實現的排序方法,該演算法採用經典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題然後遞迴求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。 合

演算法設計與分析——歸併排序

演算法思想 虛擬碼 MERGE-SORT A[1…n] 1.If n= 1, done. 2.Recursively sort A[ 1 . . .n/2.]and A[ [n/2]+1 . . n ] . 3.“Merge” the 2 sorted li

排序演算法c語言描述---歸併排序

                排序算法系列學習,主要描述氣泡排序,選擇排序,直接插入排序,希爾排序,堆排序,歸併排序,快速排序等排序進行分析。文章規劃:一。通過自己對排序演算法本身的理解,對每個方法寫個小測試程式。 具體思路分析不展開描述。二。通過《大話資料結構》一書的截圖,詳細分析該演算法 。 在此,推薦

希爾、快速歸併排序總結

冒泡、選擇、插入排序的效率都是O(N^2),但插入排序稍微快一些 歸併排序的效率是O(NlogN),希爾排序的效率大約是O(N(logN)2),快速排序需要O(N*logN)時間,希爾排序效率不穩定O(N*N(1.3~2)),理論上歸併比快速還要快,但歸併要建立

js演算法:分治法-歸併排序

歸併排序(合併排序)是一個遞迴演算法,這個演算法的理解其實可以藉助下面這個圖: 對於原始的陣列2,1,3,8,5,7,6,4,10,在整個過程執行的是順序是途中紅色編號1-20。雖然我們描述中說的是程式先分解,再歸併,但實際過程是一邊分解一邊歸併,前半部分分先排好序,後半

排序演算法:二路歸併排序(java)

public class MergeSort { /** * * @param array 待排序陣列 * @param temp 輔助陣列 * @param start 開始下標 * @param end 結束下標

Luogu 1177 - 【模板】快速排序 - [快速排序][歸併排序][無旋Treap]

題目連結:https://www.luogu.org/problemnew/show/P1177 題意:輸入 $n$ 以及後續 $n$ 個整數,讓你將這 $n$ 個整數從小到大排序輸出。   歸併排序(用時: 121ms / 記憶體: 1568KB): #inclu

五十道程式設計小題目 --- 28 八大排序演算法 java 之 07歸併排序

7. 歸併排序(Merge Sort) 基本思想: 歸併(Merge)排序法是將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然後再把有序子序列合併為整體有序序列。 歸併排序示例:   合併方法: 設r[

演算法設計與分析------歸併排序求序列最小值問題

題目要求:用分治法實現找一個序列最小值的功能那我剛學演算法,就引用書上的程式碼寫這個程式。書籍:《演算法設計與分析》(第2版)#include<iostream>using namespace std;void Merge(int r[],int r1[],int