算法:排序 二叉树深度时间复杂度? 归并和快速排序实践?B树时间复杂度?

概念:以某个值或值的集合为输入,将输入转换成输出的计算步骤的一个序列。

O(1)<O(logn)<O(n)<O(nlogn)<O(n*n)

算法的时间复杂度用来衡量随问题规模n的增长执行次数的增长率。

常见排序:

插入排序

      遍历数组,遍历到i时,a0,a1...ai-1是已经排好序的,取出ai,从ai-1开始从后向前和每个比较大小(从前向后比的话需要考虑移动其他元素的问题),如果小于,则将此位置元素向后移动,继续先前比较,如果不小于,则放到正在比较的元素之后。可见相等元素比较是,原来靠后的还是拍在后边,所以插入排序是稳定的。

 冒泡排序

      冒泡排序的名字很形象,实际实现是相邻两节点进行比较,大的向后移一个,经过第一轮两两比较和移动,最大的元素移动到了最后,第二轮次大的位于倒数第二个,依次进行。这是最基本的冒泡排序,还可以进行一些优化。

      优化一:如果某一轮两两比较中没有任何元素交换,这说明已经都排好序了,算法结束,可以使用一个Flag做标记,默认为false,如果发生交互则置为true,每轮结束时检测Flag,如果为true则继续,如果为false则返回。

      优化二:某一轮结束位置为j,但是这一轮的最后一次交换发生在lastSwap的位置,则lastSwap到j之间是排好序的,下一轮的结束点就不必是j--了,而直接到lastSwap即可,代码如下:

归并排序

时间复杂度O(nlogn)

public static void merge(int[] a, int low, int mid, int high) {
    int[] temp = new int[high - low + 1];
    System.out.println("temp:" + Arrays.toString(temp));
    int i = low;// 左指针
    int j = mid + 1;// 右指针
    int k = 0;
    // 把较小的数先移到新数组中
    while (i <= mid && j <= high) {
        if (a[i] < a[j]) {
            temp[k++] = a[i++];
            System.out.println("把较小的数先移到新数组中1:" + Arrays.toString(temp));
            System.out.println("k:"+k);
        } else {
            temp[k++] = a[j++];
            System.out.println("把较小的数先移到新数组中2:" + Arrays.toString(temp));
            System.out.println("k:"+k);
        }
    }
    // 把左边剩余的数移入数组
    while (i <= mid) {
        temp[k++] = a[i++];
        System.out.println("把左边剩余的数移入数组:" + Arrays.toString(temp));

    }
    // 把右边边剩余的数移入数组
    System.out.println("j:"+j);
    while (j <= high) {
        temp[k++] = a[j++];
        System.out.println("把右边边剩余的数移入数组:" + Arrays.toString(temp));
    }
    // 把新数组中的数覆盖nums数组
    for (int k2 = 0; k2 < temp.length; k2++) {
        a[k2 + low] = temp[k2];
    }
}

public static void mergeSort(int[] a, int low, int high) {
    int mid = (low + high) / 2;
    if (low < high) {
        // 左边
        mergeSort(a, low, mid);
        // 右边
        mergeSort(a, mid + 1, high);
        // 左右归并
        merge(a, low, mid, high);
        System.out.println(Arrays.toString(a));
    }

}

public static void main(String[] args) {
    int a[] = { 51, 46, 20, 18};
    mergeSort(a, 0, a.length - 1);
    System.out.println("排序结果:" + Arrays.toString(a));
}
一.其实就是数学里的必用习惯:直接表示法。
1.将原始问题原子性得表达为不可再拆解得独立子问题,一一映射到逻辑步骤里。(有几个子问题就有几个步骤)
2.把用到的不同含义的变量(此题只把循环用到的表示出来了)独立表示出来如左边数组的第一位最后一位,右边数组的第一位最后一位

package test.MainTEST;

import java.util.Arrays;

import static test.MainTEST.TestRunTimeSelfException.INSTANCEOne;

public class MainTest {

    public static void main(String[] args) {
        //测试是否能捕获throw
        MainTest main = new MainTest();
        //System.out.println(INSTANCEOne.getCode());
        /*归并排序*/
        int[] a = {54,52,30, 20,10,5,98,67,69};
        int length = a.length;
        main.merge(a, 0, length / 2 - 1, length / 2, length - 1, length);
        System.out.println("结果数组" + Arrays.toString(a));
    }

    private int[] merge(int[] a, int leftFirst, int leftLast, int rightFirst, int rightLast, int len) {

        int[] temp = new int[len];

        if (len == 1) {
            return a;
        }
        int leftLen = leftLast - leftFirst + 1;
        if(leftLen>=2) {
            //子左分割,归并
            int sonLeftLast = leftFirst + leftLen/2 -1;
            int sonrightFirst = sonLeftLast + 1;
            this.merge(a, leftFirst, sonLeftLast, sonrightFirst, leftLast, leftLen);
        }
        int rightLen = len - leftLen;
        if(rightLen>=2){
            //子右分割,归并
            int sonLeftLast = rightFirst + rightLen / 2 - 1;
            int sonrightFirst = sonLeftLast + 1;
            this.merge(a, rightFirst, sonLeftLast, sonrightFirst, rightLast, rightLen);
        }
        
        //归并最外层
        int i = leftFirst,j=rightFirst,k=0;

        while (i <= leftLast & j <= rightLast)
        {
            if (a[i] <= a[j]) {
                temp[k++] = a[i++];
            } else {
                temp[k++] = a[j++];
            }
        }
        //左边剩余的处理(此时右边刚好处理完)
        while (i <= leftLast)
        {
            temp[k++] = a[i++];
        }
        //右边的剩余处理(此时左边刚好处理完)
        while (j <= rightLast)
        {
            temp[k++] = a[j++];
        }

        for (int m = 0; m < temp.length; m++) {
            a[leftFirst++] = temp[m];
        }
        System.out.println("temp数组:"+Arrays.toString(temp));
        System.out.println("每归并一次:" + Arrays.toString(a));
        return a;
    }
}

快速排序

 

 

二叉树的时间复杂度

平衡二叉排序树深度为Log2|n+1,时间复杂度为O(Log2|n)

如果二叉排序树完全不平衡,则二叉排序树的深度为n,退化为顺序查找,时间复杂度为O(n)。

综上,二叉排序树的时间复杂度介于O(Log2|n)和O(n)之间。因此为了提高查询效率,二叉排序树最好构造成平衡的。

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值