java:N叉樹堆排序基本原理與例項
阿新 • • 發佈:2018-11-26
堆排序(Heapsort)概念:是指利用堆這種資料結構所設計的一種排序演算法;
堆(英語:heap) 概念:電腦科學中一類特殊的資料結構的統稱。堆通常是一個可以被看做一棵樹的陣列(集合)物件。
原理圖(圖示為三叉樹):
擴充套件說明:
堆排序的每次新建堆排序其實是"氣泡排序"和"父節點和子節點間排序"的綜合結果!
若父節點和子節點間採取的"排序方式2",則:
1. 當N叉樹的N趨近於1,導致層數越多,每個父節點的子節點數越少的時候. "氣泡排序
2. 當N趨近於陣列總長度,每個父節點的子節點越多,層越少排序方式2"作用的次數就越多,而當N等於陣列長度-1的時候,實際是一個父節點和子節點的排序問題,此時堆排序等於"排序方式2".
注: "排序方式2"極值篩選效率越高,則整體堆排序越快,因為每次父子節點間排序僅需要知道極值即可;
以下為採用選擇排序作為"排序方式2"的陣列堆排序和集合堆排序程式碼:(java)
陣列堆排序:
import java.util.Arrays; import java.util.Objects; /** * 利用N叉樹對int陣列進行堆排序(更改陣列型別可應用到char byte short long float double陣列, * 當陣列長度比 N 小時,實際就是直接選擇排序; */ public class Test04_HeapSort { private static final int FORK_OF_NUMBER=5;//N叉樹的N設為常量值 //程式入口 public static void main(String[] args) { int[] ints={42,31,34,3,56,78,90,12,34,56,78,2,12,1};//等待排序陣列 heapSort(ints);//呼叫排序方法,引數即等待排序陣列 System.out.println(Arrays.toString(ints));//輸出結果 } //排序方法 private static void heapSort(int[] ints){ int length = ints.length;//陣列長度 //迴圈次數等於陣列個數 for (int heapSortTime = 0; heapSortTime < length; heapSortTime++) { Objects.requireNonNull(ints,"陣列為空,哥們兒!");//判空 int sortLength=length-heapSortTime;//新N叉樹元素個數,即剩餘需要排序元素個數 int last=(sortLength-1)%FORK_OF_NUMBER;//末尾不成整樹叉的子節點數量 int times=(last==0)?(sortLength-1)/FORK_OF_NUMBER:((sortLength-1)/FORK_OF_NUMBER)+1;//父節點數量,不完整父節點也算 //迴圈父節點數個次數 for (int time = 1; time <= times; time++) { //迴圈子節點數次 for (int i = 0; i < (last==0?FORK_OF_NUMBER:last); i++) { //第一個子節點下標 int firstSonForkIndex=(last==0)?sortLength-FORK_OF_NUMBER*time+heapSortTime:sortLength-FORK_OF_NUMBER*(time-1)-last+heapSortTime; //父節點下標 int fatherForkIndex=(firstSonForkIndex-heapSortTime+FORK_OF_NUMBER-1)/FORK_OF_NUMBER-1+heapSortTime; //選擇排序,將極值放到父節點 if(ints[firstSonForkIndex+i]<ints[fatherForkIndex]){ int term=ints[firstSonForkIndex+i]; ints[firstSonForkIndex+i]=ints[fatherForkIndex]; ints[fatherForkIndex]=term; } } } } } }
集合堆排序:(由於集合可以使用泛型,所以可以排序任意型別元素的List集合,(但呼叫方法時需要重寫Comparator介面的compare(T,T)方法),
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Objects;
/**
* 利用N叉樹對List集合進行堆排序,只要定義排序方法的Comparator比較規則(new Comparator或者用
* Lambda表示式皆可),當集合長度比 N 小時,實際就是直接選擇排序;
*/
public class Test04_HeapSort_AnyArray {
private static final int FORK_OF_NUMBER=77;//N叉樹的N設為常量值
//程式入口
public static void main(String[] args) {
ArrayList<Integer> arrayList=new ArrayList<>();//定義等待排序集合
arrayList.add(6);//新增元素
arrayList.add(2);//新增元素
arrayList.add(5);//新增元素
arrayList.add(90);//新增元素
arrayList.add(1);//新增元素
arrayList.add(2);//新增元素
heapSort(arrayList,(o1,o2) -> o2-o1);//呼叫排序方法,Lambda表示式傳入Comparator比較器
System.out.println(arrayList);//輸出排序結果
}
private static <T> void heapSort(ArrayList<T> arrayList, Comparator<T> cp){
int length = arrayList.size();//集合元素個數
//迴圈次數等於集合元素個數
for (int heapSortTime = 0; heapSortTime < length; heapSortTime++) {
Objects.requireNonNull(arrayList,"陣列為空,哥們兒!");//判空
int sortLength=length-heapSortTime;//新N叉樹元素個數,即剩餘需要排序元素個數
int last=(sortLength-1)%FORK_OF_NUMBER;//末尾不成整樹叉的子節點數量
int times=(last==0)?(sortLength-1)/FORK_OF_NUMBER:((sortLength-1)/FORK_OF_NUMBER)+1;//父節點數量,不完整父節點也算
//迴圈父節點數個次數
for (int time = 1; time <= times; time++) {
//迴圈子節點數次
for (int i = 0; i < (last==0?FORK_OF_NUMBER:last); i++) {
//第一個子節點下標
int firstSonForkIndex=(last==0)?sortLength-FORK_OF_NUMBER*time+heapSortTime:sortLength-FORK_OF_NUMBER*(time-1)-last+heapSortTime;
//父節點下標
int fatherForkIndex=(firstSonForkIndex-heapSortTime+FORK_OF_NUMBER-1)/FORK_OF_NUMBER-1+heapSortTime;
//選擇排序,將極值放到父節點
if(cp.compare(arrayList.get(firstSonForkIndex+i),arrayList.get(fatherForkIndex))>0){
T term=arrayList.get(firstSonForkIndex+i);
arrayList.set(firstSonForkIndex+i,arrayList.get(fatherForkIndex));
arrayList.set(fatherForkIndex,term);
}
}
}
}
}
}
程式設計思想:
1. 演示說明了堆排序的基本實現原理,指出了其實際為兩種排序綜合作用結果的特點;
2. 在集合排序程式碼中,排序方法加入Comparator比較器介面,可供呼叫者自定義比較元素方式;
3. 採用三目運算子根據子節點數確定底層迴圈次數,減少使用if else判斷語句;
另外:
帶物件型別引數的方法第一步判空等,都是一個程式設計師的基本修養......