1. 程式人生 > >多執行緒歸併排序

多執行緒歸併排序

歸併排序是典型的分治演算法,所以可以用多執行緒來解決,在Linux平臺上進行多執行緒程式設計,必須在編譯時連結Linuxthread庫,如下圖所示:


因為比較簡單,就直接上程式碼了,講各種排序的部落格也比較多。

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>

int *array_master;

/* 歸併函式 */
void merge(int arr[], int left, int middle, int right)
{
    int i, j, k;
    int half1 = middle - left + 1; /* 陣列前一半的資料量 */
    int half2 = right - middle;  /* 陣列後一半的資料量 */

    int first[half1], second[half2]; /* 宣告兩個臨時陣列,
                                     儲存前半部分資料和後半部分資料 */

    /* 從 arr 陣列複製 left 到 right 之間前半部分的資料 */
    for (i = 0; i < half1; i++) 
        first[i] = arr[left + i]; 

    /* 從 arr 陣列複製 left 到 right 之間後半部分的資料 */
    for (j = 0; j < half2; j++) 
        second[j] = arr[middle + 1 + j];

    i = 0;
    j = 0;
    k = left;

    /* 比較兩個臨時陣列的數,找出當前最小的數,然後按序存入 arr */
    while (i < half1 && j < half2) 
    {

        if (first[i] <= second[j]) 
        {
            arr[k] = first[i];
            ++i; 
        }
        else 
        {
            arr[k] = second[j];
            j++;
        }

        k++; /* arr 陣列的索引 */
    }

    /* 將臨時陣列中剩餘的數存入 arr 陣列 */
    while (i < half1) 
    {
        arr[k] = first[i];
        i++;
        k++;
    }

    while (j < half2)
    {
        arr[k] = second[j];
        j++;
        k++;
    }
}

/* 歸併排序函式 */
void merge_sort(void* arg) 
{
    /* 變數宣告 */
    int *arr = array_master; /* 指向全域性變數 array_master 陣列 */
    int *argu = (int*)arg;
    int l = argu[0]; /* 由執行緒傳入的引數,獲得要排序資料的最小索引值 */
    int r = argu[1]; /* 由執行緒傳入的引數,獲得要排序資料的最大索引值 */

    /* 若 l==r 則不必排序 */
    if (l < r) 
    {    
        /* 宣告兩個執行緒描述符 */
        pthread_t tid1;
        pthread_t tid2;

        /* 宣告呼叫執行緒處理函式的引數 */
        int arg1[2];
        int arg2[2];

        int middle;
        middle = (l + (r - 1)) / 2;
        arg1[0] = l;
        arg1[1] = middle;
        arg2[0] = middle + 1;
        arg2[1] = r;

        /* 由於用二分法對陣列分成兩部分分別排序,
        所以存在並行的可能,這裡採用多執行緒 */
        pthread_create(&tid1, NULL, merge_sort, arg1);
        pthread_create(&tid2, NULL, merge_sort, arg2);

        /* 這裡必須等待兩部分陣列都已排序完畢,才能進行歸併,
        所以這裡呼叫 pthread_join 使得執行緒同步 */
        pthread_join(tid1, NULL);
        pthread_join(tid2, NULL);

        /* 此時歸併兩個已排序子序列 */
        merge(arr, l, middle, r);
        pthread_exit(0);
    }
}

/* 主函式 */
int main()
{
    int array[] = {1,23,4,56,7,89};
    int array_length = sizeof(array)/sizeof(array[0]);
    array_master = array;

    int arg[2];
    arg[0] = 0;
    arg[1] = array_length;

    /* 建立執行緒執行歸併排序 */
    pthread_t tid;
    pthread_create(&tid, NULL, merge_sort, arg);

    /* 程序同步 */
    pthread_join(tid, NULL);

    /* 列印已排序陣列 */
    int j;
    for (j = 0; j < array_length; j++) 
            printf("%d\n", array_master[j]);

    return 0;
}