clllll  

认识 时间复杂度

常数时间的操作

一个操作和 样本的数据量没有 关系,每次都是固定时间内完成。
时间复杂度为一个算法流程中,常数操作数量的一个指标; 用Big O来表示

对一个算法流程非常熟悉, 发生多少 常数时间 的操作

表达式中,只要高阶项 。 也不要高阶项的系数

评价一个算法的好坏,先看时间复杂度,然后 分析不同数据样本下 实际 运行时间, 也就是常数项 时间。

选择排序

时间复杂度 O(n^2) 额外空间 O(1)

public void userSort(int[] arr) {
        System.out.println("===选择排序===");
        if (arr == null || arr.length < 2) {
            return;
        }
        // 选择排序,每次选一个最小的或者最大的,然后和当前 索引交换
        // i 从 0 遍历到 length-1, 剩下一个肯定是最大的了
        for (int i = 0; i < arr.length - 1; i++) {
            int min = i; // 保存 值最小的索引
            // 依次遍历后续每个位置
            for (int j = i + 1; j < arr.length; j++) {
                // 从 i+ 1 开始选择,前面的已经是选择好的
                if (arr[j] < arr[min]) {
                    min = j;
                }
            }
            // 遍历完成之后。min 和 i 交换
            swap(arr, i, min);
        }

    }

python 实现

def user_sort(self, arr):
   print("选择排序")
   # 选择排序
   for i in range(len(arr)):
       min_index = i
       for j in range(i+1, len(arr)):
           if arr[j] < arr[min_index]:
               min_index = j 
       
       arr[i], arr[min_index] = arr[min_index], arr[i]

冒泡排序

时间复杂度O(n^2) 空间复杂度O(1)
从0开始

public void userSort(int[] arr) {
        if(arr == null || arr.length <2){
            return;
        }
        // 冒泡排序,俩俩依次对比

        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = i + 1; j < arr.length; j++) {
                // 俩俩比较,前面的比后面的大就交换
                if (arr[i] > arr[j]) {
                    swap(arr, i, j);
                }
            }
        }
    }

从最后开始

public void userSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        // 冒泡排序,从最后一位开始,谁大,谁冒

        for (int i = arr.length - 1; i > 0; i--) {
            // 每次冒出一个最大值,索引依次递减
            for (int j = 0; j < i; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j, j + 1);
                }
            }
        }
    }

python 实现

def user_sort(self, arr):
    print("冒泡排序")
    for i in range(len(arr))[::-1]:
        for j in range(i):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]

插入排序

就是在前面已经排好序的时候,依次和前面的数据比较,如果小,就和当前元素交换,直到不能插入,就退出。
在大部分是已经排好序的时候,效果最好

 public void userSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        // 插入排序

        // 从索引1开始,0位置就是已经排好的。
        for (int i = 1; i < arr.length; i++) {

            for (int j = i - 1; j >= 0; j--) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j, j + 1);
                } else {
                    break;
                }
            }
        }
    }

python 实现
调试的时候,写了个bug,交换 = 写成 ==了。我去。看了半天。

def user_sort(self, arr):
    print("插入排序")
    for i in range(1, len(arr)):
        for j in range(i)[::-1]:
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
            else:
                break

归并排序

从中间分成左右俩部分,分别排好序,然后合并。
调试的时候,userSort方法忘记调用mergeSort了,看了半天。我了个去。。。

public void userSort(int[] arr) {
    if (arr == null || arr.length < 2) {
        return;
    }
    // 归并排序
    mergeSort(arr, 0, arr.length - 1);
}

public void mergeSort(int[] arr, int l, int r) {

    if (l == r) {
        // 递归的结束条件。
        return;
    }

    int mid = l + ((r - l) >> 1);
    mergeSort(arr, l, mid); // 排左边, 递归
    mergeSort(arr, mid + 1, r); // 排 右边, 递归

    merge(arr, l, mid, r); // 合并

}

public void merge(int[] arr, int l, int m, int r) {
    // 需要辅助数组,大小是当前r-l + 1
    int[] helpArry = new int[r - l + 1];
    int helpArryCurrentIndex = 0; // 辅助数组当前索引
    int lCurrentIndex = l; // 左边当前索引
    int rCurrentIndex = m + 1; // 右边当前索引

    // 循环条件,左边当前索引还没有到mid,以及 右边当前索引还没有到r
    while (lCurrentIndex <= m && rCurrentIndex <= r) {
        // 判断当前左 右俩个数谁进入 辅助数组
        if (arr[lCurrentIndex] <= arr[rCurrentIndex]) {
            // 左边 数小,进入辅助数组
            helpArry[helpArryCurrentIndex] = arr[lCurrentIndex];
            // 左边索引加1
            lCurrentIndex += 1;
        } else {
            // 右边 数小, 进入辅助数组
            helpArry[helpArryCurrentIndex] = arr[rCurrentIndex];
            // 右边索引加1
            rCurrentIndex += 1;
        }
        // 辅助数组索引 必加1
        helpArryCurrentIndex += 1;
    }

    // 上面while循环条件结束,有可能左边还有数,也有可能右边还有数

    while (lCurrentIndex <= m) {
        // 左边还有数
        helpArry[helpArryCurrentIndex++] = arr[lCurrentIndex++];
    }

    while (rCurrentIndex <= r) {
        // 右边还有数
        helpArry[helpArryCurrentIndex++] = arr[rCurrentIndex++];
    }

    // 把辅助数组的数,拷贝到arr数组中
    for (int i = 0; i < helpArry.length; i++) {
        arr[l + i] = helpArry[i];
    }

}

python 实现
注意,一点要检查 传递进来的数组的大小,负责容易死循环,
或者 递归结束条件改为 l>=r

class InsertSort(ArrayUtil):
    def user_sort(self, arr):
        print("插入排序")
        for i in range(1, len(arr)):
            for j in range(i)[::-1]:
                if arr[j] > arr[j+1]:
                    arr[j], arr[j+1] = arr[j+1], arr[j]
                else:
                    break

class MergeSort(ArrayUtil):

    def user_sort(self, arr):
        if len(arr) == 0:
            return
        self.merge_sort(arr, 0, len(arr) - 1)
    
    def merge_sort(self, arr, l, r):
        # print(f"l == r {l}, {r}")
        if l == r:
            return
        
        m = l + ((r-l) >> 1)
        # print(f"{l} + {r}  ==> {m}")

        self.merge_sort(arr, l, m)
        self.merge_sort(arr, m + 1, r)

        self.merge(arr, l, m, r)

    def merge(self, arr, l, m, r):
        help_arry = []
        l_cur_index = l
        r_cur_index = m + 1

        while l_cur_index <= m and r_cur_index <= r:
            if arr[l_cur_index] <= arr[r_cur_index]:
                help_arry.append(arr[l_cur_index])
                l_cur_index += 1
            else:
                help_arry.append(arr[r_cur_index])
                r_cur_index += 1
        
        while l_cur_index <= m:
            help_arry.append(arr[l_cur_index])
            l_cur_index += 1

        while r_cur_index <= r:
            help_arry.append(arr[r_cur_index])
            r_cur_index += 1
        
        for index, item in enumerate(help_arry):
            arr[l + index] = item 

快速排序1.0

[ <5 5 >5 ]

1:选最后一个元素作为划分值
2:小于这个元素的放在左边,大于这个元素的放在右边
依次对左右俩个子序列操作步骤 1,2
时间复杂度O(N^2)(最坏情况)
123456789

@Override
public void userSort(int[] arr) {
    quickSort(arr, 0, arr.length - 1);
}

public static void quickSort(int[] arr, int l, int r) {
    // 递归退出条件
    if (l >= r) {
        return;
    }

    // 分割
    int[] p = pararion(arr, l, r);

    quickSort(arr, l, p[0]);
    quickSort(arr, p[1], r);

}

public static int[] pararion(int[] arr, int l, int r) {
    int less = l - 1; // 小于区域
    int more = r; // 大于区域
    // 当 l 和大于区域 相撞,停止
    // 划分值为最后一个元素 arr[r]
    while (l < more) {

        if (arr[l] < arr[r]) {
            // 当前元素小于 划分值 ,小于区域 和 l 交换
            // 小于区域 右扩(less++), 看下一个元素(l++)
            less++;
            swap(arr, less, l); // 因为 小于区域下一个 元素 可能是划分值,
            l++;
        } else if (arr[l] > arr[r]) {
            // 当前元素 大于 划分值,大于区域左扩(more 减一 )

            // 当前元素和 大于区域的下一个元素交换
            swap(arr, --more, l);

        } else {
            // 当前元素等于 划分值, 看下一个元素
            l++;

        }

    }
    // 划分完之后,大于区域的左边元素和划分值(最后一个元素)交换
    swap(arr, more, r);

    // 把小于区域 的 索引 和 大于区域 的 索引返回去
    return new int[] { less, more };

}

python 实现

def user_sort(self, arr):
    if len(arr) <= 1:
        return
    self.quick_sort(arr, 0, len(arr) - 1)

def quick_sort(self, arr, l, r):
    if l >= r:
        return 
    
    less, more = self.partition(arr, l, r)

    self.quick_sort(arr, l, less)
    self.quick_sort(arr, more, r)

def partition(self, arr, l, r):
    less = l - 1
    more = r

    while l < more:
        if arr[l] < arr[r]:
            less += 1
            arr[less], arr[l] = arr[l], arr[less]
            l += 1
        elif arr[l] > arr[r]:
            more -= 1
            arr[l], arr[more] = arr[more], arr[l]
        else:
            l += 1
    
    arr[more], arr[r] = arr[r], arr[more]

    return less, more

快速排序2.0

【<5 =5 > 5】

快速排序3.0

划分值 很偏,所以最坏。划分值如果在中间,就很好。
划分值随机选择一个。和最后一个位置交换。
O(NlogN)
空间复杂度O(logN)

 swap(arr, l + (int) (Math.random() * (r - l + 1)), r); //随机选择一个位置后最后一个位置交换

posted on 2022-04-25 23:18  llcl  阅读(76)  评论(0编辑  收藏  举报