演算法設計:從一個很大很大的數組裡找前N個最大數的思路之一
阿新 • • 發佈:2019-02-16
這裡先講一種類似於快速排序的方法。注意題目要求,不要求完全排序,只要求最快解決問題!這個題是我面試NI公司時,對方問我的。原話是從1億個資料裡,找出前一百個最大的。
首先看原始碼吧:
void main(int a[], int start, int end, int N)//從陣列a裡,找出前N個最大的。如果是a[100],則start = 0, end = 99.注意這個索 引問題
{
int mid = (start + end)/2;
int i = start, j = end;
while(i<j)
{
while(i<j && a[i]<=a[mid])
i++;
while(i<j && a[j]>=a[mid])
j--;
swap(a[i], a[j]);
}
/*注意這個while出來之後,i一定是等於j的,且從i 到 end是較大的那一端*/
if(end-i+1 == N)
return;
if(end - i+1 > N)
findMaxN(a, i, end, N);
else
findMaxN(a, start, i, N - (end -i +1));
}
再來詳細說說思路,如果您看懂了快速排序對此一定不會陌生。首先拿a[mid] 做基準值,然後讓i, j從兩端開始遍歷,如果索引小的那一端資料小於基準值a[mid], 就往前遍歷,如果 左邊的大於了a[mid], while迴圈會跳出,記住這時的a[i] 是大於a[mid],
然後類似的思路,從j那一端遍歷,當右邊的資料a[j ] 小於基準值a[mid],則小while迴圈會跳出。然後會執行swap()這個函式,將兩個值進行交換 。 這樣最外面的while迴圈出來之後,i一定是等於j的,注意這裡i 和j不一定等於當前域中的mid。而且從i到end都是較大的,然後看看較大的那一端的資料有多少個,然後進行遍歷。
如果已經等於要找的N個,則跳出函式。如果大於N,則要從i到end為區間內接著找;如果小於N,比如說要找前50個最大的,結果end-i+1才等於20,也就是從i到end有20個較大的數,這就需要從 start(第一次時,可以認為是0)到i 區間內再找50-20 = 30個最大的。
至於swap的函式,利用引用實現如下:
void swap(int &a, int &b)
{
int temp = a;
a = b;
b= temp;}
最後說說,如果這個函式執行完畢了,我怎麼訪問找到的最大的N個數呢? 很簡單,假設陣列長度為n, 從a[n-1], a[n-2]。。。順序取N個數,就是找到的最大的前N個數據了!這個演算法的最大情況時間複雜度是o(n的平方),最好情況是o(n), 平坦下來也是o(n).
等我空我介紹第二種思路,上面程式碼是即興寫的,原始碼我一會上傳。
http://download.csdn.net/detail/yanzi1225627/4684046
首先看原始碼吧:
void main(int a[], int start, int end, int N)//從陣列a裡,找出前N個最大的。如果是a[100],則start = 0, end = 99.注意這個索 引問題
{
int mid = (start + end)/2;
int i = start, j = end;
while(i<j)
{
while(i<j && a[i]<=a[mid])
i++;
while(i<j && a[j]>=a[mid])
j--;
swap(a[i], a[j]);
}
/*注意這個while出來之後,i一定是等於j的,且從i 到 end是較大的那一端*/
if(end-i+1 == N)
return;
if(end - i+1 > N)
findMaxN(a, i, end, N);
else
findMaxN(a, start, i, N - (end -i +1));
}
再來詳細說說思路,如果您看懂了快速排序對此一定不會陌生。首先拿a[mid] 做基準值,然後讓i, j從兩端開始遍歷,如果索引小的那一端資料小於基準值a[mid], 就往前遍歷,如果 左邊的大於了a[mid], while迴圈會跳出,記住這時的a[i] 是大於a[mid],
然後類似的思路,從j那一端遍歷,當右邊的資料a[j ] 小於基準值a[mid],則小while迴圈會跳出。然後會執行swap()這個函式,將兩個值進行交換 。 這樣最外面的while迴圈出來之後,i一定是等於j的,注意這裡i 和j不一定等於當前域中的mid。而且從i到end都是較大的,然後看看較大的那一端的資料有多少個,然後進行遍歷。
如果已經等於要找的N個,則跳出函式。如果大於N,則要從i到end為區間內接著找;如果小於N,比如說要找前50個最大的,結果end-i+1才等於20,也就是從i到end有20個較大的數,這就需要從 start(第一次時,可以認為是0)到i 區間內再找50-20 = 30個最大的。
至於swap的函式,利用引用實現如下:
void swap(int &a, int &b)
{
int temp = a;
a = b;
b= temp;}
最後說說,如果這個函式執行完畢了,我怎麼訪問找到的最大的N個數呢? 很簡單,假設陣列長度為n, 從a[n-1], a[n-2]。。。順序取N個數,就是找到的最大的前N個數據了!這個演算法的最大情況時間複雜度是o(n的平方),最好情況是o(n), 平坦下來也是o(n).
等我空我介紹第二種思路,上面程式碼是即興寫的,原始碼我一會上傳。