2020-07-20

各种排序算法的实现以及其时间复杂度和稳定性

//-------------------------------------------排序--------------------------------------------

/**
 * 总结:             最优时间复杂度           最差时间复杂度             稳定性
 *
 * 冒泡排序             O(n)                    O(n^2)                  稳定
 *
 * 选择排序             O(n^2)                  O(n^2)                 不稳定
 *
 * 插入排序             O(n)                    O(n^2)                  稳定
 *
 * 快速排序             O(nlogn)                O(n^2)                 不稳定
 *
 * 希尔排序             O(n^1.3)                O(n^2)                 不稳定
 *
 * 合并排序             O(nlogn)               O(nlogn)                稳定
 *
 *
 */
 
public void invokeSort(){
    int[] sort = {3, 4, 55, 21, 94, 49, 16, 89, 97, 56, 7};
    //        bubbleSort(sort);
    //        System.out.println("bubbleSort = " + Arrays.toString(sort));
    //        selectSort(sort);
    //        System.out.println("selectSort = " + Arrays.toString(sort));
    //        insertSort(sort);
    //        System.out.println("insertSort = " + Arrays.toString(sort));
    //        quickSort(sort, 0, sort.length - 1);
    //        System.out.println("quickSort = " + Arrays.toString(sort));
    //        shellSort(sort);
    //        System.out.println("shellSort = " + Arrays.toString(sort));
    sort = mergeSort(sort);
    System.out.println("mergeSort = " + Arrays.toString(sort));

    int searchValue = 48;
    boolean binarySearch = binarySearch(sort, searchValue);
    System.out.println("binarySearch = " + binarySearch);
}

/**
 * 冒泡排序
 * 最优时间复杂度:O(n)(比如如果数组本来就是有序的,那么我们可以在第二个循环中给个Boolean值进行判断,如果经过一次外围
 * 循环之后内循环中没有交换过数据,此时已经可以证明数组是有序的了,内循环就相当于执行了时间复杂度为O(1)的几行代码,此时就
 * 可以退出循环排序了)
 * 最差时间复杂度:O(n^2)(两次循环)
 * 稳定性:稳定(冒泡排序循环过程中不会导致两个相同的数据进行交换,还是会保持原来的首尾顺序)
 *
 * @param sort
 */
private void bubbleSort(int[] sort) {
    int length = sort.length;
    for (int i = length - 1; i > 0; i--) {
        for (int j = 0; j < i; j++) {
            if (sort[j] > sort[j + 1]) {
                int middleValue = sort[j + 1];
                sort[j + 1] = sort[j];
                sort[j] = middleValue;
            }
        }
    }
}

/**
 * 选择排序
 * 最优时间复杂度:O(n^2)(无法经过一次循环就能判断是否有序,因为哪怕数组是有序的,依然要执行相同顺序的代码)
 * 最差时间复杂度:O(n^2)(两次循环)
 * 稳定性:不稳定(举个例子,序列{5 8 5 2 9},我们知道第一遍选择第1个元素5会和2交换,
 * 那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法)
 *
 * @param sort
 */
private void selectSort(int[] sort) {
    // 升序每次选择最大的情况
    //        int length = sort.length;
    //        for (int i = length ; i > 0 ; i--) {
    //            int maxValue = 0;
    //            for (int j = 1; j < i; j++) {
    //                if (sort[j] > sort[maxValue]) {
    //                    maxValue = j;
    //                }
    //            }
    //            int middleValue = sort[i];
    //            sort[i] = sort[maxValue];
    //            sort[maxValue] = middleValue;
    //        }

    // 降序每次选择最小的情况
    int length = sort.length;
    for (int i = 0; i < length - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < length; j++) {
            if (sort[j] < sort[minIndex]) {
                minIndex = j;
            }
        }
        int middleValue = sort[i];
        sort[i] = sort[minIndex];
        sort[minIndex] = middleValue;
    }
}

/**
 * 插入排序
 * 最优时间复杂度: O(n)(比如本来就是有序的,那么进行插入的内循环应为一判断就退出内循环了,
 * 那么内循环只是相当于执行固定的几句代码就退出循环了)
 * 最差时间复杂度: O(n^2)(两次循环)
 * 稳定性:  稳定(插入排序不改变相同元素之间的顺序)
 *
 * @param sort
 */
private void insertSort(int[] sort) {
    int length = sort.length;
    for (int i = 1; i < length; i++) {
        for (int j = i; j > 0; j--) {
            if (sort[j] < sort[j - 1]) {
                int middleValue = sort[j - 1];
                sort[j - 1] = sort[j];
                sort[j] = middleValue;
            } else {
                break;
            }
        }
    }
}

/**
 * 快速排序
 * 最优时间复杂度:O(nlogn)(当每次往下进行划分排序的时候都是等半的情况,此时的这种情况时间复杂度是logn)
 * 最差时间复杂度:O(n^2)(考虑本来就有序的情况,此时往下划分都是只有完整的一半,
 * 相当于冒泡排序或者选择排序每次循环都只找到了一个最值的情况)
 * 稳定性:不稳定(比如:{5,2,7,9,10,2}的情况,当把5当做middle值,那么先从右边开始游标往左行驶时,把最后面的
 * 那个2放到了5的位置,那么此时2的原始首尾顺序已经改变了)
 *
 * @param sort
 */
private void quickSort(int[] sort, int firstIndex, int lastIndex) {

    if (firstIndex >= lastIndex) {
        return;
    }
    int middleValue = sort[firstIndex];
    int cursorFirst = firstIndex;
    int cursorLast = lastIndex;
    while (cursorFirst < cursorLast) {
        while (cursorLast > cursorFirst && sort[cursorLast] >= middleValue) {
            cursorLast--;
        }
        sort[cursorFirst] = sort[cursorLast];
        while (cursorLast > cursorFirst && sort[cursorFirst] < middleValue) {
            cursorFirst++;
        }
        sort[cursorLast] = sort[cursorFirst];
    }
    sort[cursorFirst] = middleValue;

    quickSort(sort, firstIndex, cursorFirst - 1);
    quickSort(sort, cursorFirst + 1, lastIndex);
}

/**
 * 希尔排序
 * 最优时间复杂度:根据步长序列的不同而不同,最好的情况是n1.3
 * 最差时间复杂度:O(n^2)
 * 稳定性: 不稳定(比如{5,1,1,6},此时步长为2时,第二个1会跟5对换,那么此时两个1的前后顺序就发生了变化)
 *
 * @param sort
 */
private void shellSort(int[] sort) {
    int length = sort.length;
    int step = length / 2;
    while (step > 0) {
        for (int i = step; i < length; i++) {
            for (int j = i; j >= step; j = j - step) {
                if (sort[j] < sort[j - step]) {
                    int temp = sort[j];
                    sort[j] = sort[j - step];
                    sort[j - step] = temp;
                }
            }
        }
        step = step / 2;
    }
}

/**
 * 归并排序
 * 最优时间复杂度:nlogn(无论何种情况,都是等分往下一分为二)
 * 最差时间复杂度:nlogn(一分为二)
 * 稳定性:稳定(归并排序不改变相同元素之间的顺序)
 *
 * @param sort
 */
private int[] mergeSort(int[] sort) {
    int length = sort.length;
    if (length <= 1) {
        return sort;
    }
    int num = length / 2;

    int[] left = mergeSort(Arrays.copyOf(sort, num));
    int[] right = mergeSort(Arrays.copyOfRange(sort, num, length));

    return merge(left, right);
}

private int[] merge(int[] left, int[] right) {
    int leftCursor = 0;
    int rightCursor = 0;
    int leftLength = left.length;
    int rightLength = right.length;
    int sort[] = new int[leftLength + rightLength];
    int sortCursor = 0;
    while (leftCursor < leftLength && rightCursor < rightLength) {
        if (left[leftCursor] <= right[rightCursor]) {
            sort[sortCursor] = left[leftCursor];
            leftCursor++;
        } else {
            sort[sortCursor] = right[rightCursor];
            rightCursor++;
        }
        sortCursor++;
    }
    for (int i = leftCursor; i < leftLength; i++) {
        sort[sortCursor] = left[i];
        sortCursor++;
    }
    for (int i = rightCursor; i < rightLength; i++) {
        sort[sortCursor] = right[i];
        sortCursor++;
    }
    return sort;
}


/**
 * 二分查找
 *
 * @param sort
 * @param searchValue
 */
private boolean binarySearch(int[] sort, int searchValue) {
    int length = sort.length;
    if (length == 0) {
        return false;
    }
    int middle = length / 2;
    if (searchValue == sort[middle]) {
        return true;
    } else if (searchValue > sort[middle]) {
        return binarySearch(Arrays.copyOfRange(sort, middle + 1, length), searchValue);
    } else {
        return binarySearch(Arrays.copyOfRange(sort, 0, middle - 1), searchValue);
    }

}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353