认识 时间复杂度
常数时间的操作
一个操作和 样本的数据量没有 关系,每次都是固定时间内完成。
时间复杂度为一个算法流程中,常数操作数量的一个指标; 用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); //随机选择一个位置后最后一个位置交换
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统