1. 程式人生 > >java:N叉樹堆排序基本原理與例項

java:N叉樹堆排序基本原理與例項

堆排序(Heapsort)概念:是指利用堆這種資料結構所設計的一種排序演算法;

堆(英語:heap) 概念:電腦科學中一類特殊的資料結構的統稱。堆通常是一個可以被看做一棵樹的陣列(集合)物件。

原理圖(圖示為三叉樹):

 擴充套件說明:

    堆排序的每次新建堆排序其實是"氣泡排序"和"父節點和子節點間排序"的綜合結果!  

    若父節點和子節點間採取的"排序方式2",則:

    1.  當N叉樹的N趨近於1,導致層數越多,每個父節點的子節點數越少的時候. "氣泡排序

"作用的次數就越多,而當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判斷語句;

另外:

    帶物件型別引數的方法第一步判空等,都是一個程式設計師的基本修養......