都說堆排序是時間複雜度最小的排序演算法,講了各種堆排序的好,我這裡就不贅述了,今天花了乙個下午和半個晚上的時間算是差不多研究明白了堆排序。其實堆排序的邏輯並不是特別複雜,如果理解了就會覺得沒有那麼難,但是寫**的實現的時候,還是需要考慮很多事情的。反正我是被繞暈過的~
首先,寫一下我對堆排序思想的認識。堆排序主要分為以下兩個步驟:
1、由待排序的陣列,構建乙個最大堆(或者最小堆)。最大堆的意思就是說,任何乙個非葉子節點的值不大於(或者不小於)其左右孩子的值;
2、由最大堆的根元素於最末葉子結點交換,獲取到最大值(因此根元素就是最大值)。將交換後的堆,重複1的步驟,變成最大堆。重複步驟2。直到取完所有元素,出去的元素就是已經排好序的。
下面結合圖講一下整個思路:
1、最大堆的構建過程。(圖中a為待排序的元素,將它表示為乙個二叉樹如下所示,綠色數字表示該元素在陣列中對應的下標)
(1)將待排序的陣列用二叉樹的形式表示出來,則對應於任意下標為 i 的結點i,其父節點下標為(i-1)/2,左孩子結點為2*i+1,右孩子結點下標對應為2*i+2;
(2)對於非葉子結點的元素,從下標最大的開始(本例中為i=4,a[4]=16的元素),判斷其是否符合最大堆的要求,即該結點值是否大於它所有的葉子結點。
如果不滿足條件,將該結點與其葉子結點中較大的數進行交換(如i=3時,a[3]=2<14,故交換2與14的值);
如果滿足條件,比較下乙個非葉子結點。(如i=4時,a[4]=16大於它所有的葉子結點,進行i=3時的判斷)
一直重複上述過程,知道所有非葉子結點均遍歷完成。
【注意】這裡有一點要很注意,我在寫程式的時候,一開始忽略了,也比繞暈了。那就是,比如i=1的時候,不簡單是僅僅比較它與左右葉子結點的大小就可以了,當它的葉子結點是其他結點的根節點時,還需要進一步判斷,它們是否符合最大堆的條件。這裡是要用遞迴來實現的。(手畫的圖,有助於理清思路)
2、獲得最大堆之後,就開始推排序。堆排序的基本思想,就是將根元素a[0]與下標最大的數進行交換(這一過程實際上是取出最大的元素,此時的根元素就是最大的元素了),再對a[0]~a[8]執行1的步驟,即將它們變成乙個最大堆,然後再取根元素(此時的根元素就是該樹a[0]~a[8]中最大的)。由此迴圈下去,直到只剩最後乙個元素,即是最小的元素。(下圖是排序過程的示意圖)
void createmaxtree(int a, int num, int i);//最大堆生成函式,引數包括陣列,陣列大小,根節點對應的下標
void swap(int a, int x, int y);//交換函式,引數分別是陣列,需要交換的兩個數在陣列中對應的下標
int main()
; int num = sizeof(a) / sizeof(int);
int i_num = (num - 1) / 2;
for (int k = num; k > 0; k--)//外層迴圈用於堆排序中,交換後依次取出前k個數作為新陣列,呼叫生成最大堆的函式
swap(a, k-1, 0);//特別注意這是k-1,否則會出現陣列越界,此時k是陣列的長度
} for (int j = 0; j < num; j++)
return 0;
}
void createmaxtree(int a, int num,int i)//函式實現的功能是,給定乙個陣列,陣列大小,對應根節點的下標,將根節點下標之下的樹變成乙個最大堆
else
if (a[father] < a[childmax])//將較大的數與根節點交換
} else
} }if ((leftchild * 2 + 1) < num) //判斷此時的孩子結點,是否是其他結點的父結點
if ((rightchild * 2 + 1) < num)//同理,對此時的右葉子操作
}
void swap(int a, int x, int y)
排序演算法 堆排序
1 什麼是堆 首先它是一顆完全二叉樹,並且父結點的值大於子節點的值 最大堆 或父結點的值小於子結點的值 最小堆 小根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最小者的堆稱為小根堆,又稱最小堆。大根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最大者,稱為大根堆,又稱最大堆。2 堆...
排序演算法 堆排序
花了一晚上時間研究堆排序,這個排序困擾了哥很久,終於搞清楚了。一 堆的定義 1.父結點的鍵值總是大於或等於 小於或等於 任何乙個子節點的鍵值 2 每個結點的左子樹和右子樹都是乙個二叉堆 都是最大堆或最小堆 二 已知結點 i 則它的子結點 為2 i 1 與 2 i 2 父節點為 i 1 2 三 堆排序...
排序演算法 堆排序
由於不經常使用,之前學習看過的演算法都給忘了。現在把他們寫下來,記錄下來,以方便以後查閱。本篇文章的 即為堆排序的 主函式中是對輸入檔案中的序列進行排序,並將結果輸出到乙個檔案中。這是一種形式類似於google codejam的測試方法。include include using namespace...