1206 字
6 分钟
数据结构与算法
算法基础
查找算法
二分查找
最简单的查找算法, 面对有序列表, 每次从列表中间查找, 最多需要 次查找即可完成, 而简单查找至多需要 步
示例(C):
int binarySearch(int *arr, int len, int target) { int low = 0; int high = len - 1;
while (low <= high) { int mid = (low + high) / 2; int guess = arr[mid]; if (guess == target) return mid; else if (guess > target) { high = mid - 1; } else { low = mid + 1; } } return -1;}示例(Python):
def binary_search(arr, item): low = 0 high = len(arr) - 1
while low <= high: mid = (low + high) // 2 guess = arr[mid] if guess == item: return mid elif guess > item: high = mid - 1 else: low = mid + 1
return -1排序算法
冒泡排序
最容易实现的排序算法, 原理是通过不断比较相邻元素大小, 将较小的元素提至列表前而将较大的元素提至列表后
时间复杂度:
-
最坏: , 当整个列表逆序时
-
最好: , 当列表已经有序时
-
平均:
空间复杂度:
- , 由于是原地排序算法, 不需要额外存储空间
示例(C):
void bubbleSort(int *arr, size_t len){ int temp; for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - i - 1; j++) { if (arr[j] > arr[j + 1]) { temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } }}示例(Python):
def bubble_sort(arr): for i in range(len(arr) - 1): #减不减1都可以 for j in range(0, len(arr) - i - 1): if arr[j] > arr[j + 1]: arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
def bubble_sort_optimized(arr): #更喜欢的写法, 列表有序时只需要遍历一次 n = len(arr) flag = True while flag: flag = False for i in range(n - 1): if arr[i] > arr[i + 1]: flag = True arr[i], arr[i + 1] = arr[i + 1], arr[i] n -= 1选择排序
原理是每次都从待排序数据中找到最小的元素并添加到已排序序列的末尾, 重复操作直至排序完成
时间复杂度:
- 无论输入数据是否有序, 都要进行 次操作, 固定为
空间复杂度:
- , 由于是原地排序算法, 不需要额外存储空间
示例(C):
void selectionSort(int *arr, int len) { int temp; for (int i = 0; i < len; i++) { int min_idx = i; for (int j = i + 1; j < len; j++) { if (arr[j] < arr[min_idx]) { min_idx = j; } } temp = arr[i]; arr[i] = arr[min_idx]; arr[min_idx] = temp; }}示例(Python):
def selection_sort(arr): for i in range(len(arr)): min_idx = i for j in range(i + 1, len(arr)): if arr[j] < arr[min_idx]: min_idx = j arr[i], arr[min_idx] = arr[min_idx], arr[i]
return arr快速排序
原理是使用分治法Divide and Conquer的思想, 从列表中选取一个基准元素pivot, 将列表分为两部分: 一部分小于基准元素, 一部分大于基准元素. 然后递归对这两部分进行排序.
时间复杂度:
- 最坏: , 当列表几乎有序时
- 最好:
- 平均:
空间复杂度:
- 由于采用了递归, 快速排序会占用栈空间, 最差情况下为, 最好情况下为
示例(Python):
def quick_sort(arr): if len(arr) < 2: #基线条件 return arr else: #递归条件 pivot = arr[0] left = [x for x in arr[1:] if x < pivot] mid = [x for x in arr if x == pivot] right = [x for x in arr[1:] if x > pivot] return quick_sort(left) + mid + quick_sort(right)数据结构
数组和链表
数组在内存中是连续的, 因此需要提前申请固定大小的内存空间, 而链表在内存中往往是不连续的, 因此对于单向链表来说每个节点都要存储下一个节点的地址, 而双向链表则需要存储节点前后两个节点的地址.
- 数组随机访问速度快, 而链表不能随机访问, 必须从第一个节点开始访问
- 数组插入和删除效率低, 内存固定, 而链表插入和删除效率高, 使用动态内存, 利用率高
读取复杂度:数组;链表插入/删除复杂度:数组;链表
递归
递归原理是函数调用自身, 实现相应目的. 一般来说每个递归函数都有基线条件和递归条件. 递归条件给出了进入递归的条件, 基线条件则用来限制函数无限递归.
使用示例(C):
int Fibonacci(int n) { if (n < 2) return n; //基线条件 else return Fibonacci(n - 1) + Fibonacci(n - 2); //递归条件}使用示例(Python):
def fibonacci(n): if n < 2: #基线条件 return n else: #递归条件 return fibonacci(n - 1) + fibonacci(n - 2)使用递归能有效解决很多问题, 但由于其反复进行堆栈操作, 某些时候会占用很大内存. 此时便可以考虑将递归结构改写成循环结构.
部分信息可能已经过时