Java基礎(chǔ)算法:堆排,快排咏连,二分查找

Java基礎(chǔ)算法:堆排盯孙,快排,二分查找

1. 堆排

滿二叉樹:所有葉結(jié)點(diǎn)都有同樣的深度捻勉,每個(gè)內(nèi)部結(jié)點(diǎn)都有兩個(gè)兒子

完全二叉樹:若二叉樹的高度為h镀梭,除第h層外刀森,其他各層(1 ~ h -1)的結(jié)點(diǎn)數(shù)都達(dá)到了最大個(gè)數(shù)踱启,第h層從右向左連續(xù)若干結(jié)點(diǎn);也就是說一個(gè)結(jié)點(diǎn)有右結(jié)點(diǎn)研底,也一定有左結(jié)點(diǎn)

滿二叉樹是一種特殊的完全二叉樹埠偿,滿二叉樹一定是完全二叉樹,但完全二叉樹不一定是滿二叉樹

代碼:

public class HeapSort {

    public static void main(String[] args) {
        int[] nums = {5, 1, 6, 3, 7, 2, 9, 4, 0, 8};
        //進(jìn)行排序
        heapSort(nums);
        System.out.println("排序后: " + Arrays.toString(nums));
    }

    /**
     * 進(jìn)行排序
     */
    private static void heapSort(int[] nums) {
        //創(chuàng)建最大堆
        create(nums);
        //打印出最大堆
        System.out.println("最大堆: " + Arrays.toString(nums));
        for (int i = nums.length - 1; i > 0; i--) {
            swap(nums, 0, i);
            siftDown(nums, 0, i);
        }
    }

    /**
     * 從小到達(dá)排序榜晦,建立最大堆
     * 創(chuàng)建的時(shí)間復(fù)雜度為 O(N)
     * 由于葉結(jié)點(diǎn)沒有子結(jié)點(diǎn)冠蒋,直接從最后一個(gè)非葉結(jié)點(diǎn)的結(jié)點(diǎn)開始
     */
    private static void create(int[] nums) {
        int len = nums.length;
        //最后一個(gè)非葉結(jié)點(diǎn)是第 n/2 個(gè)結(jié)點(diǎn)
        for (int i = len / 2; i > -1; i--) {
            siftDown(nums, i, len);
        }
    }

    /**
     * 數(shù)組角標(biāo)從0開始,左兒子結(jié)點(diǎn)為 2 * i + 1乾胶;右兒子結(jié)點(diǎn)為 2 * i + 2抖剿;
     *排序的時(shí)間復(fù)雜度為 O(NlogN)
     * @param nums  數(shù)組
     * @param index 向下調(diào)整的父結(jié)點(diǎn)編號(hào)
     * @param last  數(shù)組的最后角標(biāo)
     */
    private static void siftDown(int[] nums, int index, int last) {
        //左兒子結(jié)點(diǎn)
        int left = index * 2 + 1;
        //右兒子結(jié)點(diǎn)
        int right = left + 1;
        //將父結(jié)點(diǎn)賦予臨時(shí)結(jié)點(diǎn)
        int temp = index;
        //左兒子結(jié)點(diǎn)沒有越界并且父結(jié)點(diǎn)上的值小于左兒子結(jié)點(diǎn)的值
        if (left < last && nums[left] > nums[index]) {
            //將左兒子結(jié)點(diǎn)賦予臨時(shí)結(jié)點(diǎn)
            temp = left;
        }
        //右兒子結(jié)點(diǎn)沒有越界并且父結(jié)點(diǎn)上的值小于右兒子結(jié)點(diǎn)的值
        if (right < last && nums[right] > nums[temp]) {
            //將右兒子結(jié)點(diǎn)賦予臨時(shí)結(jié)點(diǎn)
            temp = right;
        }
        //父結(jié)點(diǎn)和臨時(shí)結(jié)點(diǎn)不相同朽寞,證明兒子結(jié)點(diǎn)有比父結(jié)點(diǎn)大的情況
        if (index != temp) {
            //交換結(jié)點(diǎn)的值
            swap(nums, index, temp);
            //再次進(jìn)行篩選
            siftDown(nums, temp, last);
        }
    }

    /**
     * 交換值
     */
    private static void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

結(jié)果:

最大堆: [9, 8, 6, 4, 7, 2, 5, 3, 0, 1]
排序后: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

2. 快排

尋找中間值角標(biāo),右側(cè)先開始查找比中間值小的斩郎,然后左側(cè)尋找比中間值大的脑融,然后交換,直到中間值左側(cè)都比中間值小缩宜,右側(cè)都比中間值大

代碼

public class QuickSort {
    public static void main(String[] args) {
        int[] nums = {5, 1, 6, 3, 7, 2, 9, 4, 0, 8};
        quickSort(nums, 0, nums.length - 1);
        System.out.println(Arrays.toString(nums));
    }

    private static void quickSort(int[] nums, int low, int high) {
        // 角標(biāo)未越界
        if (low < high) {
            int index = findPartIndex(nums, low, high);
            quickSort(nums, low, index - 1);
            quickSort(nums, index + 1, high);
        }
    }

    /**
     *  找到一個(gè)樞軸值肘迎,這個(gè)臨界值左邊的數(shù)都比這個(gè)樞軸值小,右邊都比這個(gè)樞軸值大
     *
     * @param nums  數(shù)組
     * @param left  最左側(cè)索引
     * @param right 最右側(cè)索引
     * @return 樞軸值的角標(biāo)
     */
    private static int findPartIndex(int[] nums, int low, int high) {
        // 臨時(shí)角標(biāo)
        int i = low;
        int j = high;
        // 臨時(shí)值锻煌,對比值
        int temp = nums[low];
        while (i < j) {
            // 先從右側(cè)開始比較妓布,若當(dāng)前最右側(cè)的值大于等于樞軸值,角標(biāo)減 1
            while (i < j && nums[j] >= temp) {
                j--;
            }
            // 左側(cè)開始比較宋梧,若當(dāng)前最左側(cè)的值小于等于樞軸值匣沼,角標(biāo)加 1
            while (i < j && nums[i] <= temp) {
                i++;
            }

            // 到了這一步,就說明右側(cè)找到了一個(gè)比樞軸值小
            // 而左側(cè)找到了一個(gè)比樞軸值大的值
            if (i < j) {
                // 進(jìn)行交換,將大的值放在右邊捂龄,小的值放在左面
                int n = nums[j];
                nums[j] = nums[i];
                nums[i] = n;
            }
        }
        // 出了while循環(huán)肛著,說明 i == j ,因?yàn)?i 在++ 跺讯, j 在--
        // 將 j 位置上的值賦予最左側(cè)
        // 其中 j 就是臨界角標(biāo)
        nums[low] = nums[j];
        // 將之前的基準(zhǔn)值枢贿,賦予樞軸值角標(biāo)位置
        nums[j] = temp;
        return j;
    }
}

3. 二分查找

二分查找作用于一個(gè)有序的序列,有兩種思路:循環(huán)和遞歸

代碼:

public class BinarySearch {
    public static void main(String[] args) {
        int[] nums = {11, 13, 23, 24, 34, 46, 67, 89, 98};
        int key = 23;
        //循環(huán)
        int v = binarySearch(nums, key);
        System.out.println("循環(huán):" + v);
        //遞歸
        int i = binarySearch(nums, 0, nums.length, key);
        System.out.println("遞歸:" + i);
        //Java api
        int index = Arrays.binarySearch(nums, key);
        System.out.println("Java api:" + index);
    }

    /**
     * 利用循環(huán)
     * 從Java api中復(fù)制出來的
     */
    private static int binarySearch(int[] a, int key) {
        int low = 0;
        int high = a.length - 1;
        while (low <= high) {
            //早起JDk使用的(low + high) / 2刀脏,但會(huì)有有臨界值bug
            //當(dāng)數(shù)組的大小足夠大時(shí)局荚,low + high有可能超出int范圍
            //可以使用 low + (high - low)/2
            int mid = (low + high) >>> 1;//速度更快
            int midVal = a[mid];
            if (midVal < key) {
                low = mid + 1;
            } else if (midVal > key) {
                high = mid - 1;
            } else {
                return mid; //找到key
            }

        }
        return -1;  // 沒有找到key
    }

    /**
     * 利用遞歸
     */
    private static int binarySearch(int[] a, int fromIndex, int toIndex, int key) {
        rangeCheck(a.length, fromIndex, toIndex);
        int mid = (fromIndex + toIndex) >>> 1;
        int midVal = a[mid];
        if (midVal < key) {
            return binarySearch(a, mid + 1, toIndex, key);
        } else if (midVal > key) {
            return binarySearch(a, fromIndex, mid - 1, key);
        } else if (midVal == key) {
            return mid;
        }
        return -1;
    }

    /**
     * 檢查是否越界
     */
    private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
        if (fromIndex > toIndex) {
            throw new IllegalArgumentException(
                    "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
        }
        if (fromIndex < 0) {
            throw new ArrayIndexOutOfBoundsException(fromIndex);
        }
        if (toIndex > arrayLength) {
            throw new ArrayIndexOutOfBoundsException(toIndex);
        }
    }
}

結(jié)果:

循環(huán):2
遞歸:2
Java api:2

4. 最后

網(wǎng)上看到別人面試問到這些,再次復(fù)習(xí)學(xué)習(xí)下

有錯(cuò)誤請指出

共勉 : )

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末愈污,一起剝皮案震驚了整個(gè)濱河市耀态,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌暂雹,老刑警劉巖首装,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異杭跪,居然都是意外死亡仙逻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門涧尿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來系奉,“玉大人,你說我怎么就攤上這事姑廉∪绷粒” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵桥言,是天一觀的道長萌踱。 經(jīng)常有香客問我葵礼,道長,這世上最難降的妖魔是什么并鸵? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任章咧,我火速辦了婚禮,結(jié)果婚禮上能真,老公的妹妹穿的比我還像新娘赁严。我一直安慰自己,他們只是感情好粉铐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布疼约。 她就那樣靜靜地躺著,像睡著了一般蝙泼。 火紅的嫁衣襯著肌膚如雪程剥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天汤踏,我揣著相機(jī)與錄音织鲸,去河邊找鬼。 笑死溪胶,一個(gè)胖子當(dāng)著我的面吹牛搂擦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哗脖,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼瀑踢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了才避?” 一聲冷哼從身側(cè)響起橱夭,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎桑逝,沒想到半個(gè)月后棘劣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡楞遏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年茬暇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片橱健。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡而钞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拘荡,到底是詐尸還是另有隱情,我是刑警寧澤撬陵,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布珊皿,位于F島的核電站网缝,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蟋定。R本人自食惡果不足惜粉臊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驶兜。 院中可真熱鬧扼仲,春花似錦、人聲如沸抄淑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肆资。三九已至矗愧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郑原,已是汗流浹背唉韭。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留犯犁,地道東北人属愤。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像酸役,于是被迫代替她去往敵國和親春塌。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 課程介紹 先修課:概率統(tǒng)計(jì)簇捍,程序設(shè)計(jì)實(shí)習(xí)只壳,集合論與圖論 后續(xù)課:算法分析與設(shè)計(jì),編譯原理暑塑,操作系統(tǒng)吼句,數(shù)據(jù)庫概論,人...
    ShellyWhen閱讀 2,255評論 0 3
  • B樹的定義 一棵m階的B樹滿足下列條件: 樹中每個(gè)結(jié)點(diǎn)至多有m個(gè)孩子事格。 除根結(jié)點(diǎn)和葉子結(jié)點(diǎn)外惕艳,其它每個(gè)結(jié)點(diǎn)至少有m...
    文檔隨手記閱讀 13,181評論 0 25
  • 第一章 緒論 什么是數(shù)據(jù)結(jié)構(gòu)? 數(shù)據(jù)結(jié)構(gòu)的定義:數(shù)據(jù)結(jié)構(gòu)是相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合驹愚。 第二章...
    SeanCheney閱讀 5,742評論 0 19
  • 原文出處:http://www.cnblogs.com/maybe2030/p/4715035.html引文出處:...
    明教de教主閱讀 9,117評論 0 7
  • 目錄 0.樹0.1 一般樹的定義0.2 二叉樹的定義 1.查找樹ADT 2.查找樹的實(shí)現(xiàn)2.1 二叉查找樹2.2 ...
    王偵閱讀 7,124評論 0 3