從大資料檔案中挑選K個最小的記錄

2021-09-11 02:09:14 字數 3808 閱讀 7603

大根堆:

根結點(稱為堆頂)的關鍵字是堆裡所有結點關鍵字中最大者,稱為大根堆,又稱最大堆(大頂堆)。大根堆要求根節點的關鍵字既大於或等於左子樹的關鍵字值,又大於或等於右子樹的關鍵字值。

heap是一種資料結構具有以下的特點:

1)  完全二叉樹;

2)heap中儲存的值是偏序;

小根堆(最大堆): 父節點的值小於或等於子節點的值;

大根堆(最小堆): 父節點的值大於或等於子節點的值;

堆的儲存

一般都用陣列來表示堆,i結點的父結點下標就為(i–1)/2。它的左右子結點下標分別為2 * i + 1和2 * i + 2。如第0個結點左右子結點下標分別為1和2。

堆排序堆建好之後堆中第0個資料是堆中最大的資料。取出這個資料再執行下堆的刪除操作。這樣堆中第0個資料又是堆中最大的資料,重複上述步驟直至堆中只有乙個資料時就直接取出這個資料。

堆的操作:insert

插入乙個元素:新元素被加入到heap的末尾,然後更新樹以恢復堆的次序。

每次插入都是將新資料放在陣列最後。可以發現從這個新資料的父結點到根結點必然為乙個有序的數列,現在的任務是將這個新資料插入到這個有序資料中——這就類似於直接插入排序中將乙個資料併入到有序區間中。

堆的操作:removemax

按定義,堆中每次都刪除第0個資料。為了便於重建堆,實際的操作是將最後乙個資料的值賦給根結點,然後再從根結點開始進行一次從上向下的調整。調整時先在左右兒子結點中找最大的,如果父結點比這個最小的子結點還大說明不需要調整了,反之將父結點和它交換後再考慮後面的結點。相當於從根結點將乙個資料的「下沉」過程。

/***    實驗題目:

*        從大資料檔案中挑選k個最小的記錄

*    實驗目的:

*        掌握外排序的過程及堆的應用演算法設計

*    實驗內容:

*        編寫程式,從大資料檔案中挑選k個最小的記錄。假設記憶體工作區的大小為k,

*    模擬這個過程,並輸出每趟的結果。假設整數序列為(15, 4, 97, 64, 17, 32, 108,

*    44, 76, 9, 39, 82, 56, 31, 80, 73, 255, 68),從中挑選5個最小的整數。

*    備註:

*       為了簡單,假設每個記錄僅僅包含整型關鍵字,用全域性變數fi模擬存放所有的記錄,

*    r[1..k]存放大根堆。

*/#include

#include

#define max_size        (100)

#define max_key         (32767)                     //  最大關鍵字值∞

#define k   5                                       //  記憶體工作區可容納的記錄個數

typedef int key_type;                               //  關鍵字型別

typedef struct

file_type;                                         //  檔案型別

file_type fi;                                       //  定義輸入檔案,為全域性變數

key_type r[k + 1];                                  //  存放大根堆

/*------------------輸入檔案初始化-------------------*/

static void initial(void)

;for(i = 0; i < n; i++)                          //  將n個記錄存放到輸入檔案中

fi.recs[i] = a[i];

fi.length = n;                                  //  輸入檔案中有n個記錄

fi.cur_rec = -1;                                //  輸入檔案中當前位置為-1

}/*-------------------從輸入檔案中取乙個記錄r--------------------*/

static bool get_one_rec(key_type &r)

}/*-------------------顯示堆中所有記錄--------------------*/

static void disp_heap(void)

/*---------------篩選為大根堆演算法------------------*/

static void sift(int low, int high)

else

break;                                      //  篩選結束

}r[i] = tmp;                                         //  被篩選結點的值放入最終位置

}/**

*   功能:

*       從輸入檔案fi中挑選k個最小的記錄。

*   演算法思路:

*       首先,從fi中取出開頭的k個記錄存放在r中,將其調整為乙個大根堆r,

*   然後依次取出fi的其餘記錄r,若r小於大根堆r的根結點r[1],用r替代r[1],

*   再篩選為大根堆。當fi所有記錄取出完畢,r中即為k個最小的記錄。

*/static void select_k(void)

for(i = k / 2; i >= 1; i--)             //  建立初始堆 i = 2, 1

sift(i, k);

printf("開頭%d個記錄建立的大根堆:", k);

disp_heap();

while(get_one_rec(r))                   //  從輸入檔案fi中取出其餘的記錄

else

printf("\t不需要篩選\n");}}

int main(void)

測試結果:

開頭5個記錄建立的大根堆:97 64 15 4 17

處理32:       需要篩選,結果:64 32 15 4 17

處理108:      不需要篩選

處理44:       需要篩選,結果:44 32 15 4 17

處理76:       不需要篩選

處理9:        需要篩選,結果:32 17 15 4 9

處理39:       不需要篩選

處理82:       不需要篩選

處理56:       不需要篩選

處理31:       需要篩選,結果:31 17 15 4 9

處理80:       不需要篩選

處理73:       不需要篩選

處理255:      不需要篩選

處理68:       不需要篩選

最終結果: 31 17 15 4 9

大資料檔案讀取方法

filepath 1.txt step 1024 1024 1m str r n start 0 i 1 count 0 do while i 1 echo count file get contents 讀取大檔案方法 param unknown patha 檔案路徑 param unknown ...

批量去重大資料檔案

作為乙個linux的學徒,分享一下自己解決這個小問題的心得,在處理這個問題時使用了乙個小技巧感覺很適用,個人發覺linux的終端真滴是非常強大,下面就詳細地介紹這個問題以及解決辦法吧 問題描述 由於要分析登入ip所以有很多放有不同ip的日誌檔案,首先要將所有log檔案合併成乙個log檔案,並將每乙個...

C 從資料夾中讀取txt資料檔案

txt檔案的命名以數字遞增的方式來命名,樣例如下 資料檔案放在工程下,讀取的思路是 先獲取資料夾下的檔案的數量,然後以數字自增的方式獲取檔案的名稱 使用tostring 方法 具體 如下 提取資料,讀到arraylist al中 元素為每一行的資料 private void read string ...