堆排序\鏈表實現局部排序

之前面試時被問一個問題:有10萬個亂序的數,要前5個最大(或最小)的數?
做爲一個沒好好學算法的人,尚未算法時間、空間複雜度的概念,只提出了冒泡、快速排序等,而後取前5。這顯然不是合理的作法。面試

讀了幾本書,有一點點心得,下面介紹兩個作法:
假設:輸入爲[31,5,12,24,41,63,7,61,42,21,9,123,24...] ,總數爲N=100000,要求前M=5個最大的數算法

  1. 對10萬個創建二叉堆,而後應用堆排序5次,即取出前5個最大(或最小)的數。
    只是一個可行的方法,在此不敖述,具體可參見《數據結構與算法分析:C語言描述》、《數據結構(C語言版)》嚴蔚敏等書中的堆排序。數據結構

  2. 考慮:可否維護一個數據結構用來存儲排好序的5個數,要求若是輸入數大於5箇中最小的數,就將其插入至正確位置,並刪除最小的數。這樣對輸入進行一次遍歷,便可找出最大的5個數。
    此處想到的是用單鏈表,首先對輸入中前5個數字升序排序,插入空的鏈表中。app

//簡單冒泡排序,輸入少,對總體性能影響可忽略不計
for(int j=1; j<M; j++){
    for(int k=0; k<M-j; k++){
        if(input[k]>input[k+1]){
            tmp = input[k];
            input[k] = input[k+1];
            input[k+1]=tmp;
        }
    }
}
for(int i=0; i<M; i++){
    Insert(input[i],L,P);//依次插入鏈表
    P = P->Next;
}

圖片 1.png

Position Tmp,TmpCell;
for( ; i<N; i++){ //對其他輸入進行一次遍歷
    P = Header(L); //表頭
    do{
        Tmp = P;//暫存前驅元,保存位置
        P = P->Next;//第一個元素
        if( input[i] <= P->Value ){ //小於第一個元素或者後面的某一個元素
            if(P != L->Next){ //input[i]大小介於第一個元素與此位置的元素
                Insert(in[i],L1,Tmp); //插入
                TmpCell = L1->Next;
                L1->Next = TmpCell->Next;
                free( TmpCell ); //擠出第一個元素,也就是5+1=6箇中最小的元素
            }
            break;
        }else if(input[i] > P->Value && IsLast( P, L )){ //若是大於最後一個(也就是最大的)元素
            Insert(in[i],L,P); //插入到最後
            TmpCell = L->Next; L->Next = TmpCell->Next; free(TmpCell); //刪除第一個元素(6箇中最小的)
            break;
        }
    } while( !IsLast(P, L) );
}

插入多是這樣的:
圖片 2.pngtypecho

刪除首元多是這樣的:
圖片 3.png性能

小結:當輸入大數據量,而只需前m個最大(最小)值時,應用鏈表不失爲一個好辦法,它只對輸入進行一次遍歷,時間複雜度O(N),空間也只不過額外是一個含6個元素的鏈表大小而已。
歡迎指教。大數據

相關文章
相關標籤/搜索