分治算法--尋找第k大數


  問題描述:給定線性序集中n個元素和一個整數k,1≤k≤n,要求找出這n個元素中第k大的元素,(這里給定的線性集是無序的)。

  其實這個問題很簡單,直接對線性序列集qsort,再找出第k個即可。但是這樣的時間復雜度就是qsort的時間復雜度O(nlogn)。有沒有更快的方法呢?看到網上有一種解法是采取了快排的思路,但是稍微坐了些改動,然后時間復雜度能夠接近O(n)。因為最近剛剛寫了快排的實現,所以在這我就再把這個實現一次吧。

  解題思路:與快排不同的是,這里只對划分出來的其中一組進行遞歸處理。任意選定一個pivotIndex,pivotValue = arr[pivotIndex]。經過一次划分后,pivotValue存儲在storeIndex的位置,storeIndex把數組划分為兩部分。比pivoteValue大的在前面,比pivotValue小的存儲在后面(此時前后兩部分是沒有排好序的)。那么storeIndex位置的pivotValue就肯定是第storeIndex大的數。然后用K於storeIndex比較,如果K<storeIndex,那么說明第K大一定在右邊,那么再對右邊進行划分即可。如果K>storeIndex,那么說明第K大一定在左邊,那么再對左邊進行划分。然后遞歸,最后就可以得到第K大。

#include <stdio.h>

void swap(int *a, int *b)
{
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}

int partition(int arr[], int left, int right, int pivotIndex)
{
    int storeIndex = left;
    int pivotValue = arr[pivotIndex];
    int i;

    swap(&arr[pivotIndex],&arr[right]);
    
    for (i = left; i < right; i ++)
    {
        if (arr[i] > pivotValue)
        {
            swap(&arr[i],&arr[storeIndex]);
            storeIndex++;
        }
    }
    swap(&arr[storeIndex],&arr[right]);
    return storeIndex;
}

int findKMax(int arr[], int left, int right, int k)
{
    int nRet;
    int pivotIndex = left + 1;

    nRet = partition(arr,left,right,pivotIndex);
    if (nRet < k)
    {
        return findKMax(arr,nRet+1,right,k);
    }
    else if (nRet > k)
    {
        return findKMax(arr,left,nRet-1,k);
    }
        
    return nRet;
}


int main()
{
    int i,k,nRet;
    int arr[] = {8,3,4,1,9,7,6,10};

    scanf("%d",&k);
    nRet = findKMax(arr,0,7,k-1);
    
    printf("The Kth Max Number locate in %d is :%d\n",nRet,arr[nRet]);
    for (i = 0; i < 8; i++)
    {
        printf("%3d",arr[i]);
    }
    return 0;
} 
 
2013/6/17  19:55

 

  蕭蕭空間列出了很多種尋找第K大數的算法。

第二次實現該算法:

#include <stdio.h>

void swap(int arr[], int i, int j)
{
    int tmp;

    tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

int partition(int arr[], int left, int right)
{
    int value = arr[left];
    int p_insert,p_cmp;

    swap(arr,left,right);
    p_insert = p_cmp = left;

    while (p_cmp < right)
    {
        if (arr[p_cmp] < value)
        {
            swap(arr,p_insert,p_cmp);
            p_insert++;
        }
        p_cmp++;
    }
    swap(arr,p_insert,right);

    return p_insert;
}

void max_k(int arr[], int left, int right,int k)
{
    int ret = partition(arr,left,right);
    if (ret == k) return;
    else if (ret < k)
        ret = partition(arr,ret+1,right);
    else
        ret = partition(arr,left,ret);     
}

int main()
{
    int arr[] = {9,10,7,8,3,12,15,76,6};
    int i,k = 5;

    max_k(arr,0,8,k);

    for (i = 0; i < k; i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n");


    return 0;
}

2013/10/21  22:42


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM