java 排序 1和1_java實現排序(1)-插入排序

引言

排序模塊會把所有的排序算法都整理一遍,方便自己以后回身學習。在本篇博文中主要介紹了時間復雜度為O(N^2)的插入排序算法,並用demo進行實現。不過在開始之前需要學習一些基礎的數學知識,希望對大家有所幫助。筆者目前整理的一些blog針對面試都是超高頻出現的。大家可以點擊鏈接:http://blog.csdn.net/u012403290

技術點

1、4個符號(O, Ω,Θ, o)

在本排序集合模塊中,這4個符號用於表示兩個函數之間的相對增長率,他們分別讀作O(大O), Ω(omega),Θ(theta),o(小O)。

2、4個定義

①如果存在正常數c和n使得當N>=n時,T(N)<=cf(N),則記為T(N)=O(f(N))。

解釋下什么意思,如果存在兩個函數T(N)和f(N)且兩個函數圖的線是相交的,那么存在一個點n,使得兩者的值相等。其中c是一個常數。比如說10N 和N^2這兩個函數,當且僅當N=10的時候兩者相交,如下圖:

d300477be0a1922ce7226713a608e103.png

在10這個點之前,T(N)的值比f(N)小,但是f(N)的相對增長率大,在10之后會一直比T(N)大,也就是n點之后f(N)的增長率比T(N)大, 寫為10N = O(N^2)。

②如果存在正常數c和n使得當N>=n時,T(N)>=cg(N),則記為T(N)=Ω(g(N))。

和上面①的定義是差不多的,只不過是相對增長率反過來了,n點之后g(N)的增長率比T(N)小。上面的例子在這里就變成了T(N)= N^2,g(N)=10N了,也就是N^2 = Ω(10N)。

③當T(N)=O(h(N))且T(N) = Ω(h(n))時,可以用T(N) = Θ(h(N))。

現在很好理解了,意思就是兩個函數的增長率是相同的,那么就可以用Θ表示。

④如果存在正常數c和n使得當N>n時,T(N)< cp(N),則記為T(N)=o(p(N))。

乍眼一看是不是感覺和第①條很像?其實兩者最大的區別就是兩個函數圖有沒有增長率相等的情況,讀作p(N)的增長率比T(N)大,比如說下面這張圖:

e9196cd8cd72d436ebf6c48febaec308.png

現學現用的話那么就是T(N) = O(p(N))且T(N)!=Θ(p(N))

這些定義在描述算法的效率問題上會有非常大的作用。

3、上界與下界

簡單來說,在T(N) = O(f(N))中,f(N)就是T(N)的一個上界;同理,在T(N)上面的等式也可以表示成f(N) = Ω(T(N)),所以T(N)就是f(N)的一個下界。

插入排序

比較專業來說,就是:插入排序對於N個元素的排序需要進行N-1趟處理,p表示當前處理元素位置(或者是處理趟數),p=1到N-1趟中的任何一步都保證從0到p位置的順序是排好的。

通俗來說就是對於一個要排序的數據,將數據分為已排序和未排序兩部分,按順序將一個未排序的數據插入到已經排好序的有序數據中,從而得到一個新的、個數加一的有序數據,未排序的數據減一,直到數據全部是排序的。下面這張圖描述了過程:

a50aae3aaeddb97145dcd974e2266007.png

第一趟:處理8, 34是屬於已排好序的(一個值不用排序),8<34,那么繼續往前遍歷,發現前面沒數據了,那么就把8插入到34前面。

第二趟:處理64,64>34(從后面往前面比較),因為64比已排序好的最大的還要大,所以直接插入到34的后面。

第三趟:處理51,51<64,那么繼續遍歷,接着51>34,因為51比前面排好序最大的要大,所以停止遍歷,把51插入到34的后面

第四趟:處理32,32<64,那么繼續遍歷,32<51,那么還是繼續遍歷,32<34,那么還是繼續遍歷。32>8,遍歷結束,把32插入到8后面。

第五趟:處理21,21<64,那么繼續遍歷,21<51,那么繼續遍歷,21<34,那么繼續遍歷,21<32,那么繼續遍歷。21>8,遍歷結束,把21插入到8后面。

排序結束。

代碼實現

以下就是我實現的插入排序,排序對象是int型的數組:package com.brickworkers;

/**

*

*@author Brickworker

* Date:2017年4月19日下午3:25:27

* 關於類SortTest.java的描述:插入排序

* Copyright (c) 2017, brcikworker All Rights Reserved.

*/

public class SortTest{

public static void sort(int[] t) {

int j;

for (int p = 1; p < t.length; p++) {// 遍歷數組,從1下標開始,0位置一個元素不用排序

// 用temp暫存要排序的值

int temp = t[p];

// 代處理的數據,在已排好序的數組中從后往前進行比較遍歷

// 條件是:代處理的數據是否比有序的數據中某一個值小,如果小那么就需要對數組進行移位

for (j = p; j > 0 && temp < t[j - 1]; j--) {

// 數組移位,為數據的插入做准備

t[j] = t[j - 1];

}

// 把數據插入到合適的j位置

t[j] = temp;

}

}

public static void main(String[] args) {

int[] ints = { 1, 5, 4, 2, 6, 4, 6, 47, 5, 4, 12, 41, 66, 4, 2, 10, 42 };

sort(ints);

for (int i : ints) {

System.out.print(i + " ");

}

}

}

//輸出:1 2 2 4 4 4 4 5 5 6 6 10 12 41 42 47 66

我們對上面的算法進行分析,由於兩個for循環的嵌套,所以插入排序的時間復雜度為O(N^2)。如果是處理已排好序的數據來說,那么插入排序就是O(N),因為第二個循環在判斷的時候就結束了。考慮最差情況就是待處理數據是有序但是和預期相反,那么N個元素的執行次數就是:

1+2+….+(N-1) = (1+N-1)*N/2 =O(N^2)。

尾記

編程,算法是必須的;算法,數學是必須的。我有個朋友為了寫好代碼,學過數學(線代,離散),學過經濟,學過畫畫,學過文學。所以,不要覺得自己學這個沒用,看那個沒用,其實只是你還暫時沒有用到罷了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值