天天看點

GO、JAVA實作冒泡、選擇、插入排序

1. 冒泡排序

數組中每一個元素與其後一個元素進行比較,較大的或者較小的放在後面,即其與後面這個元素換位置。即第一個與第二個比,第二個與第三個比,知道倒數第二個與倒數第一個比,之後在數組的末尾就是最大或者最小的數了;之後繼續上一個步驟,不過由于上一趟排序中,最後一個數已經為有序的,是以隻需要比較到倒數第三個與倒數第二個比較;之後比較的次數逐次減少。

java代碼

private void bubbling(int[] arr){
        for (int i = 0; i < arr.length - 1; i++){
            boolean hasChange = false;
            for (int j = 0; j < arr.length - i - 1; j++){
                if(arr[j] > arr[j + 1]){
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    hasChange = true;
                }
            }
            if (!hasChange){
                break;
            }
        }
    }
           

效率問題:

慢…

進行80000個數字的排序,效率讓人心碎:

public static void main(String[] args) {
        int[] arr = new int[80000];
        Random random = new Random();
        for (int i = 0; i < arr.length; i++){
            arr[i] = random.nextInt(800000);
        }
        SortDemo sortDemo = new SortDemo();
        System.out.println(System.currentTimeMillis());
        sortDemo.bubbling(arr);
        System.out.println(System.currentTimeMillis());
    }
           

輸出如下:

1585325682398
1585325701677
           

19秒左右0.0

Go實作

func Bubbling(arr []int){
	for i := 0; i < len(arr) - 1; i++ {
		count := false
		for j := 0; j < len(arr) - i - 1; j++ {
			if (arr[j] > arr[j + 1]) {
				temp := 0
				temp = arr[j]
				arr[j] = arr[j + 1]
				arr[j + 1] = temp
				count = true
			}
		}
		if(!count){
			break;
		} 	
	}
}
           

效率問題:

也是一個慢字…畢竟冒泡 傷不起

80000個數字進行排序

func main(){
	arr := make([]int, 80000)
	t := time.Now()
	fomat := t.UnixNano()
	rand.Seed(fomat)
	for i := 0; i < len(arr); i++{
		arr[i] = rand.Intn(80000)
	}
	t1 := time.Now()
	Bubbling(arr)
	t2 := time.Since(t1)
	fmt.Println(t2)
}
           

輸出如下:

15.9531755s
           

2. 選擇排序

思路:從數組中選出一個最大(最小)值,放入數組頭,或者數組尾,差別在于正向反向,全看自己心情,此處使用正向升序排序。每次找出最小值放入無序端的第一個,即第i個,i從0開始

廢話不多說了,就是選出最小的往前放,上代碼:

java實作

private void choice(int[] arr){
        for (int i = 0; i < arr.length - 1; i++){
            int min = arr[i];
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++){
                if (arr[j] < min){
                    min = arr[j];
                    minIndex = j;
                }
            }
            if (i != minIndex){
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
    }
           

效率問題:比起冒泡是好了不少,但時間複雜度還是O(n^2)

依然是那熟悉的80000比資料

public static void main(String[] args) {
        int[] arr = new int[80000];
        Random random = new Random();
        for (int i = 0; i < arr.length; i++){
            arr[i] = random.nextInt(800000);
        }
        SortDemo sortDemo = new SortDemo();
        System.out.println(System.currentTimeMillis());
        sortDemo.choice(arr);
        System.out.println(System.currentTimeMillis());
    }
           

輸出結果:

1585326261907
1585326268503
           

7秒左右,确實比老爺爺冒泡跑的快了點

Go實作

func choice(arr []int){
	for i := 0; i < len(arr) - 1; i++{
		min := arr[i]
		minIndex := i
		for j := i + 1; j < len(arr); j++{
			if (arr[j] < min){
				min = arr[j]
				minIndex = i
			}
		}
		if (i != minIndex){
			temp := arr[i]
			arr[i] = arr[minIndex]
			arr[minIndex] = temp
		}
	}
}
           

再以80000比資料跑一遍:

func main(){
	arr := make([]int, 80000)
	t := time.Now()
	fomat := t.UnixNano()
	rand.Seed(fomat)
	for i := 0; i < len(arr); i++{
		arr[i] = rand.Intn(80000)
	}
	t1 := time.Now()
	choice(arr)
	t2 := time.Since(t1)
	fmt.Println(t2)
}

           

輸出如下:

6.6854358s
           

和java兄弟并排走,時間差不多

3. 插入排序

插入排序的思想是,将數組分為兩部分,左邊為有序部分,右邊為無序部分。每次從無序部分取出第一個,與有序部分分别比較,并将其插入到有序部分中,至此,有序部分加一,無序部分減一。當無序部分長度減為0時,整個數組都為有序了

如何插入?

如何了解插入這個命名呢,我們定義

insertIndex

為待被插入的下标,如果我們目前采用的比較的數比

arr[insertIndex]

小(假設是升序排列),那麼将

arr[insertIndex]

向後放,即有如下數組:

[3, 1, 2]
           

我們選1作為

insertValue

insertIndex

為0,那麼此時比較發現

arr[insertIndex] > insertValue

,那麼我們把

3

提起來往後放,放到

arr[insertIndex + 1]

的位置,之後再往前比,發現已經到了最前,就可以将

arr[insertIndex] = insertValue

;隻是舉了一個簡單的例子,如果是:

[2, 3, 4, 5, 1]
           

我們此時周遊到最後一個元素,即1,此時

insertValue = 1

insertIndex = 3

,那麼如下就是該數組的更改順序:

1. [2, 3, 4, 5, 5] insertValue = 1 insertIndex = 3
2. [2, 3, 4, 4, 5] insertValue = 1 insertIndex = 2
3. [2, 3, 3, 4, 5] insertValue = 1 insertIndex = 1
4. [2, 2, 3, 4, 5] insertValue = 1 insertIndex = 0
5. [1, 2, 3, 4, 5] 最後當  insertIndex = 0 時,給 arr[insertIndex] = insertValue
           

具體分析

int insertValue = arr[1] //需要插入進去的值
Int insertIndex = 1 -1 //将要被插入的元素的前一個元素的下标
while(insertIndex >= 0 && insertValue < arr[insertIndex]){
//上述判斷: 當元素被插入進有序部分後,如果他前面的待被插入元素仍大于等于0,	說明它前面仍然有元素
//當被插入元素的值小于它前面待被插入的元素,說明它現在沒有和目前的前一個元素比較過,
//仍然沒有确定位置,是以需要再進行比較,當它前面沒有元素或者它前面的元素的值小于它,說明它已經正确插入了有序部分
//隻要進入循環,說明它已經執行了一次插入動作,插入的實作為将待插入的元素與前面的元素換位
arr[insertIndex + 1] = arr[insertIndex]
//當換位後,目前待被插入的元素就是目前其所在位置的前一個了,
//因為該元素向前插入了一個位置,是以待被插入的元素位置也向前移動
insertIndex --
}
//因為上述循環中,如果在最後一次循環,插入元素的前面并沒有元素了,或者前一個元素比它小,但是
//insertIndex仍然減一了 是以,待插入的元素的正确位置應該是insertIndex+1
arr[insertIndex + 1] = insertValue
           

在插入排序中,我們在剛開始時總認為第一個元素自己組成了有序部分,因為也沒有其他元素和他比較大小。是以無序部分的第一個起始為1,之後每次向後加,我們隻需要給這個步驟加一個循環即可;

java實作

private void insertSort(int[] arr){
        //循環表示第幾個被插入的數  從1開始
        for (int i = 1; i < arr.length; i++){
            //需要插入的數為
            int insertValue = arr[i];
            //待被插入的下标  在待插入數的前一個
            int insertIndex = i - 1;
            //insertIndex >= 0 當insertIndex小于0時,說明待插入數之前已經沒有資料了,它是最小的數
            //insertValue < arr[insertIndex] 當待插入的數小于前一個數時,還不知道它是不是最小,它還需要與它前前一個進行
            //比較,但是在此時他已經可以插隊到他前一個數之前
            while (insertIndex >= 0 && insertValue < arr[insertIndex]){
                // 将目前的位置的數向後移動一位
                arr[insertIndex + 1] = arr[insertIndex];
                // 将下标值減一,表示将要與目前位置的前一個位置比較
                insertIndex--;
            }
            arr[insertIndex + 1] = insertValue;
        }
    }
           

效率分析:

public static void main(String[] args) {
        int[] arr = new int[80000];
        Random random = new Random();
        for (int i = 0; i < arr.length; i++){
            arr[i] = random.nextInt(800000);
        }
        SortDemo sortDemo = new SortDemo();
        System.out.println(System.currentTimeMillis());
        sortDemo.insertSort(arr);
        System.out.println(System.currentTimeMillis());
    }
           
1585326807369
1585326809251
           

比起選擇排序更快

Go實作

func insertSort(arr []int){
	for i := 1; i < len(arr); i++{
		insertValue := arr[i]
		insertIndex := i - 1
		for {
			if (insertIndex < 0 || insertValue > arr[insertIndex]){
				break
			}
			arr[insertIndex + 1] = arr[insertIndex]
			insertIndex--
		}
		arr[insertIndex + 1] = insertValue
	}
}
           

執行效率:

func main(){
	arr := make([]int, 80000)
	t := time.Now()
	fomat := t.UnixNano()
	rand.Seed(fomat)
	for i := 0; i < len(arr); i++{
		arr[i] = rand.Intn(80000)
	}
	t1 := time.Now()
	insertSort(arr)
	t2 := time.Since(t1)
	fmt.Println(t2)
}
           

執行結果:

1.8607944s
           

如果走的不快,那就多走幾步。