<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

        幾種查找數組的前K個最小值的算法

        作者:龔平   來源:本站原創   點擊數:  更新時間:2014年03月14日   【字體:

            好久沒有寫博客了,這一段時間主要在準備為將來找工作復習,今天我就總結一下關于如何查找數組的前K個最小值實現方法,查找前K個最小值實現方法很多,主要的思想包括如下的幾種:
            1、對數組進行排序,然后前K個元素就是需要查找的元素,排序的方法可以采用快速排序,但是我們知道在快速排序中如果已經是有序的數組,采用快速排序的時間復雜度是O(N^2),為了解決這種問題,通常選擇隨機選擇一個數組值pivot作為基準,將數組分為S1 =< pivot和S2 > pivot,這樣就能避免快速排序中存在的問題,或者采用隨機選擇三個元素,然后取中間值作為基準就能避免快速算法的最差時間復雜度,這種方法的前K個數字是有序的。
         
            2、既然是選擇前K個對象,那么就沒必要對所有的對象進行排序,可以采用快速選擇的思想獲得前K個對象,比如首先采用快速排序的集合劃分方法劃分集合:S1,pivot,S2,然后比較K是否小于S1的個數,如何小于,則直接對S1進行快速排序,如果K的個數超過S1,那么對S2進行快速排序,排序完成之后,取數組的前K個元素就是數組的前K個最小值。這種實現方法肯定比第一種的全快速排序要更快速。
         
            3、將數組轉換為最小堆的情況,根據最小堆的特性,第一個元素肯定就是數組中的最小值,這時候我們可以將元素保存起來,然后將最后一個元素提升到第一個元素,重新構建最小堆,這樣進行K次的最小堆創建,就找到了前K個最小值,這是運用了最小堆的特性,實質上是最小堆的刪除實現方法。這種算法的好處是實現了數組的原地排序,并不需要額外的內存空間。
         
            4、接下來的這種思想有點類似桶排序,首先給定一個K個大小的數組b,然后復制數組a中的前K個數到數組b中,將這K個數當成數組a的前K個最小值,對數組b創建最大堆,這時候再次比較數組a中的其他元素,如果其他元素小于數組b的最大值(堆頂),則將堆頂的值進行替換,并重新創建最大堆。這樣遍歷一次數組就找到了前K個最小元素。這種方法運用了額外的內存空間,特別當選擇的K值比較大時,這種方法有待于權衡一下。
            這種方法對于海量數據來說是有較好的作用,對于海量數據不能全部存放在內存中,這時候創建一個較小的數組空間,然后創建最大堆,從硬盤中讀取其他的數據,進而實現前K個數據的查找。
         
            這是比較傳統的幾種方法,當然還存在其他的選擇方式,我在這邊就不闡述了,從上面幾種方法的可知,查找方法都充分運用了運用了數據結構和算法的特性。因此數據結構的靈活運用對算法的實現有很多的好處。
         
        下面是我的實現代碼,數組中前K個元素我通過打印的方式實現,并沒有保存到新的數組中:

         

            #include<stdio.h>
            #include<stdlib.h>
            #include<string.h>
            #include<assert.h>
            #include<time.h>

            #define LEN 500000
            #define K 100

            /*堆的性質*/
            #define LEFTSON(i) (2*(i)+1)
            #define RIGHTSON(i) (2*((i)+1))
            #define PARENT(i) (((i)-1)/2)

            void swap(int *a, int *b)
            {
                    assert(a != NULL && b != NULL);

                    if(a != b)
                    {
                            *a = *a ^ *b;
                            *b = *a ^ *b;
                            *a = *a ^ *b;
                    }
            }

            int partition(int *a, int left, int right)
            {
                    int pivot = a[right];
                    int i = left;
                    int j = left - 1;

                    assert(a != NULL);

                    for(i = left; i < right; ++ i)
                    {
                            if(a[i] < pivot)
                            {
                                    ++ j;
                                    swap(&a[i],&a[j]);
                            }
                    }
                    swap(&a[j + 1],&a[right]);
                    return (j + 1);
            }

            void quicksort(int *a, int left, int right)
            {
                    int i = 0;

                    assert(a != NULL);

                    if(left < right)
                    {
                            i = partition(a,left,right);
                            quicksort(a, left, i - 1);
                            quicksort(a, i + 1, right);
                    }
            }

            int QuickSort(int *a, int size)
            {
                    assert(a != NULL);
                    quicksort(a,0,size-1);
            }

            void quickselect(int *a, int left, int right, int k)
            {
                    int i = 0;

                    assert(a != NULL && left <= k
                            && left <= right && k <= right);

                    if(left < right)
                    {
                            i = partition(a, left, right);
                            if(i + 1 <= k)
                                    quickselect(a, i + 1 , right, k);
                            else if(i > k)
                                    quickselect(a, left, i - 1, k);
                    }
            }

            void QuickSelect(int *a, int size, int k)
            {
                    assert(a != NULL);
                    quickselect(a, 0, size - 1, k);
            }

            /*最大堆*/
            void max_heapify(int *a, int left, int right)
            {
                    int tmp = 0;
                    int child = left;
                    int parent = left;

                    assert(a != NULL);

                    for(tmp = a[parent]; LEFTSON(parent) <= right;parent = child)
                    {
                            child = LEFTSON(parent);

                            if(child != right && a[child] < a[child + 1])
                                    child ++;

                            if(tmp < a[child])
                                    a[parent] = a[child];
                            else /*滿足最大堆的特性,直接退出*/
                                    break;
                    }
                    a[parent] = tmp;
            }

            /*創建最大堆*/
            void build_maxheap(int *a, int size)
            {
                    int i = 0;
                    assert(a != NULL);

                    for(i = PARENT(size); i >= 0 ; -- i)
                            max_heapify(a,i,size - 1);
            }

            /*最小堆的實現*/
            void min_heapify(int *a, int left, int right)
            {
                    int child = 0;
                    int tmp = 0;
                    int parent = left;

                    assert(a != NULL);

                    for(tmp = a[parent]; LEFTSON(parent) <= right; parent = child)
                    {
                            child = LEFTSON(parent);

                            if(child != parent && a[child] > a[child + 1])
                                    child ++;

                            if(a[child] < tmp)
                                    a[parent] = a[child];
                            else /*滿足最小堆的特性,直接退出*/
                                    break;
                    }
                    a[parent] = tmp;
            }

            /*創建最小堆*/
            void build_minheap(int *a, int size)
            {
                    int i = PARENT(size);

                    assert(a != NULL);

                    for(; i >= 0; -- i)
                            min_heapify(a, i, size - 1);
            }

            /*采用快速排序查找*/
            void find_Kmin_num_1(int *a , int size, int k)
            {
                    int i = 0;

                    assert(a != NULL);

                    QuickSort(a, size);

            #if 0
                    for(i = 0; i < k ; ++ i)
                            printf("%d\t",a[i]);

                    printf("\n");
            #endif
            }

            /*采用快速選擇實現*/
            void find_Kmin_num_2(int *a, int size, int k)
            {
                    int i = 0;

                    assert(a != NULL);

                    QuickSelect(a, size, k);

            #if 0
                    for(i = 0; i < k ; ++ i)
                            printf("%d\t",a[i]);

                    printf("\n");
            #endif
            }

            /*采用最大堆實現*/
            void find_Kmin_num_3(int *a, int size, int k)
            {
                    int i = 0;

                    int *b = malloc(sizeof(int)*k);

                    assert(a != NULL && b != NULL);

                    for(i = 0; i < k; ++ i)
                            b[i] = a[i];

                    build_maxheap(b,k);

                    for(; i < size; ++ i)
                    {
                            if(a[i] < b[0])
                            {
                                    b[0] = a[i];
            // build_maxheap(b , k);
                                    max_heapify(b,0,k - 1);
                            }
                    }
            #if 0
                    for(i = 0; i < k ; ++ i)
                            printf("%d\t",b[i]);

                    printf("\n");
            #endif
            }

            /*采用最小堆刪除元素的方式實現*/
            void find_Kmin_num_4(int *a ,int size, int k)
            {
                    int i = 0;

                    assert(a != NULL);

                    build_minheap(a, size - 1);
                    for(i = 0; i < k; ++ i)
                    {
            // printf("%d\t",a[0]);

                            /*刪除a[0],釋放a[size - 1 - i]*/
                            a[0] = a[size -1 - i];
                            min_heapify(a, 0, size - 2 - i);
                    }
            // printf("\n");
            }

            int main()
            {
                    int a[LEN];
                    int b[LEN];
                    int c[LEN];
                    int d[LEN];

                    int i = 0,j = 0;

                    clock_t _start;
                    double times = 0;

                    srand((int)time(NULL));

                    for(i = 0; i < LEN; ++ i)
                    {
                            a[i] = rand()%(LEN);
                            b[i] = a[i];
                            c[i] = a[i];
                            d[i] = a[i];

            // printf("%d\t",a[i]);
                    }
            // printf("\n");

                    _start = clock();
                    find_Kmin_num_1(a,LEN,K);
                    times = (double)(clock() - _start)/CLOCKS_PER_SEC;
                    printf("快速排序的查找需要:%f\n",times);

                    _start = clock();
                    find_Kmin_num_2(b,LEN,K);
                    times = (double)(clock() - _start)/CLOCKS_PER_SEC;
                    printf("快速選擇的查找需要:%f\n",times);

                    _start = clock();
                    find_Kmin_num_3(c,LEN,K);
                    times = (double)(clock() - _start)/CLOCKS_PER_SEC;
                    printf("最大堆的查找需要:%f\n",times);

                    _start = clock();
                    find_Kmin_num_4(d,LEN,K);
                    times = (double)(clock() - _start)/CLOCKS_PER_SEC;
                    printf("最小堆的查找需要:%f\n",times);

                    return 0;
            }

        檢測算法的性能:

         

            [gong@Gong-Computer interview]$ gcc -g minKnum.c -o minKnum
            [gong@Gong-Computer interview]$ ./minKnum
            快速排序的查找需要:0.130000
            快速選擇的查找需要:0.020000
            最大堆的查找需要:0.000000
            最小堆的查找需要:0.010000

        從結果可知,快速排序的算法效果最差,而最大堆的效果最好,最小堆的效果其次,但是最大堆運用了額外的內存空間。因此在內存空間限制的情況下,考慮最小堆是比較合適的。但是最大堆的思想確實很精妙的,運用了類似桶排序的性質。
         
        為了說明算法能否實現前K個最小值的查找,改變數組大小為50,并打印各個方法完成的情況,查找前10個數據,實驗結果如下所示:

         

            [gong@Gong-Computer interview]$ ./minKnum
            15    38    14    43    31    45    42    1    32    23    43    34    9    4    45    31    25    48    8    42    40    27    36    30    32    4    11    23    47    12    24    14    1    40    8    32    36    0    35    18    26    28    2    35    35    49    17    12    48    27   
            0    1    1    2    4    4    8    8    9    11   
            快速排序的查找需要:0.000000
            1    9    4    8    4    11    1    8    0    2   
            快速選擇的查找需要:0.000000
            11    8    9    4    2    1    8    1    4    0   
            最大堆的查找需要:0.000000
            0    1    1    2    4    4    8    8    9    11   
            最小堆的查找需要:0.000000

        從上面的實驗結果可知,四種方法都是實現了獲得前K個最小元素。

        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮