1.定义:

1.1 原地排序和非原地排序

def. 原地排序算法使用恒定的的额外空间来产生输出。

原地排序:选择排序,插入排序,希尔排序,快速排序,堆排序。

非原地排序:归并排序,计数排序,基数排序。

1.2 内部排序和外部排序

def. 当所有待排序记录不能被一次载入内存进行处理时,这样的排序就被称为外部排序。外部排序通常应用在待排序记录的数量非常大的时候。

内部排序:其他。

外部排序:归并排序以及它的变体。

1.3 稳定排序和不稳定排序

def. 待排序序列中的相等记录,排序前后位置不变。

稳定排序:​​插入排序​​​,​​基数排序​​​,​​归并排序​​​,​​冒泡排序​​​,​​计数排序​

不稳定排序:​​快速排序​​​,​​希尔排序​​​,​​简单选择排序​​​,​​堆排序​

2.快速排序:分治思想,《算法模板》

def partition(a: list, lo: int, hi: int) -> int:
i = lo + 1; j = hi
v = a[lo]
while True:
# = 防止重复数据
while a[i] <= v and i < hi: i += 1
while a[j] > v and j > lo: j -= 1
if i >= j: break
a[i], a[j] = a[j], a[i]
a[lo], a[j] = a[j], a[lo]
return j

def quickSort(a: list, lo: int, hi: int) -> list:
if lo < hi:
v = partition(a, lo, hi)
quickSort(a, lo, v - 1)
quickSort(a, v + 1, hi)
return a

if __name__ == '__main__':
a = [2,2,2,2,2,2,2,2]
res = quickSort(a, 0, len(a)-1)
print(res)

eg:

​912. 排序数组​

class Solution:
def partition(self, a: list, lo: int, hi: int) -> int:
i = lo + 1; j = hi
v = a[lo]
while True:
while a[i] <= v and i < hi: i += 1
while a[j] > v and j > lo: j -= 1
if i >= j: break
a[i], a[j] = a[j], a[i]
a[lo], a[j] = a[j], a[lo]
return j

def quickSort(self, a: list, lo: int, hi: int) -> list:
if lo < hi:
v = self.partition(a, lo, hi)
self.quickSort(a, lo, v - 1)
self.quickSort(a, v + 1, hi)
return a

def sortArray(self, nums: List[int]) -> List[int]:
return self.quickSort(nums, 0, len(nums)-1)
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:

def partition(nums, lo, hi):
p_idx = random.randint(lo, hi) # 随机选择p
nums[lo], nums[p_idx] = nums[p_idx], nums[lo] # p放置到最左边
p = nums[lo] # 选取最左边为p
l, r = lo, hi # 双指针
while l < r:
while l<r and nums[r] >= p: # 找到右边第一个<p的元素
r -= 1
nums[l] = nums[r] # 并将其移动到l处
while l<r and nums[l] <= p: # 找到左边第一个>p的元素
l += 1
nums[r] = nums[l] # 并将其移动到r处
nums[l] = p # p放置到中间l=r处
return l

def quickSort(nums, lo, hi):
if lo >= hi: return # 递归结束
mid = partition(nums, lo, hi) # 以mid为分割点
quickSort(nums, lo, mid-1) # 递归对mid两侧元素进行排序
quickSort(nums, mid+1, hi)

quickSort(nums, 0, len(nums)-1) # 调用快排函数对nums进行排序
return nums
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
def helper(nums):
if len(nums) < 2: return nums
p = nums[0]
left = [i for i in nums[1:] if i <= p]
right = [i for i in nums[1:] if i > p]
return helper(left) + [p] + helper(right)
return helper(nums)

​215. 数组中的第K个最大元素​

class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
def helper(nums):
if len(nums) < 2: return nums
key = nums[0]
left = [i for i in nums[1:] if i <= key]
right = [i for i in nums[1:] if i > key]
return helper(left) + [key] + helper(right)
return helper(nums)
def findKthLargest(self, nums: List[int], k: int) -> int:
res = self.sortArray(nums)
return res[-k]

3. 归并排序:两个不同的有序数组归并到第三个数组中,分治思想

def merge(left: list, right: list) -> list:
res = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
res.append(left[i])
i += 1
else:
res.append(right[j])
j += 1
if i == len(left):
res.extend(right[j:])
else:
res.extend(left[i:])
return res

def mergeSort(arr: list) -> list:
if len(arr) <= 1: return arr
mid = len(arr) // 2
left = mergeSort(arr[:mid])
rigit = mergeSort(arr[mid:])
return merge(left, rigit)

eg.

​21. 合并两个有序链表​

​剑指 Offer 25. 合并两个排序的链表​

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
head = cur = ListNode(0)
while list1 and list2:
if list1.val <= list2.val:
cur.next = list1
list1 = list1.next
else:
cur.next = list2
list2 = list2.next
cur = cur.next
# 合并后 list1 和 list2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
cur.next = list1 if list1 else list2
return head.next

​88. 合并两个有序数组​

class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
res = []
p1 = p2 = 0
while p1 < m or p2 < n:
if p1 == m:
res.append(nums2[p2])
p2 += 1
elif p2 == n:
res.append(nums1[p1])
p1 += 1
elif nums1[p1] <= nums2[p2]:
res.append(nums1[p1])
p1 += 1
else:
res.append(nums2[p2])
p2 += 1
nums1[:] = res

​148. 排序链表​

​剑指 Offer II 077. 链表排序​

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
# 获取中间节点并截断
def mid(self, head: ListNode) -> ListNode:
slow = head; fast = head.next
while fast and fast.next:
slow, fast = slow.next, fast.next.next
mid, slow.next = slow.next, None
return mid

def merge(self, l: Optional[ListNode], r: Optional[ListNode]) -> Optional[ListNode]:
cur = head = ListNode()
while l and r:
if l.val <= r.val:
cur.next = l
l = l.next
else:
cur.next = r
r = r.next
cur = cur.next
# 合并后 l 和 r 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
cur.next = l if l else r
return head.next

def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next: return head
left = head; right = self.mid(head)
l = self.sortList(left)
r = self.sortList(right)
return self.merge(l, r)

​剑指 Offer II 026. 重排链表​

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mid(self, head: ListNode) -> ListNode:
slow = head; fast = head.next
while fast and fast.next:
slow, fast = slow.next, fast.next.next
#截断
mid, slow.next = slow.next, None
return mid

def reverseList(self, head: ListNode) -> ListNode:
pre, cur = None, head
while cur:
# 存储当前链表的下一个节点为临时变量
tmp = cur.next
# 当前链表的下一个指向前一个链表
cur.next = pre
# pre, cur整体往后移动一个位置
pre, cur = cur, tmp
return pre

def merge(self, l1: ListNode, l2: ListNode):
h = cur = ListNode()
while l1 and l2:
cur.next = l1
l1 = l1.next
cur = cur.next
cur.next = l2
l2 = l2.next
cur = cur.next
cur.next = l1 if l1 else l2
return h.next

def reorderList(self, head: ListNode) -> None:
"""
Do not return anything, modify head in-place instead.
"""
if not head: return
l = head
r = self.mid(head)
r = self.reverseList(r)
self.merge(l, r)

​23. 合并K个升序链表​

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None

class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
if not lists:return
n = len(lists)
return self.merge(lists, 0, n-1)
def merge(self, lists, left, right):
if left == right:
return lists[left]
mid = left + (right - left) // 2
l1 = self.merge(lists, left, mid)
l2 = self.merge(lists, mid+1, right)
return self.mergeTwoLists(l1, l2)
def mergeTwoLists(self, l1, l2):
if not l1: return l2
if not l2: return l1
if l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2

​剑指 Offer 51. 数组中的逆序对​

class Solution:
def reversePairs(self, nums: List[int]) -> int:
def mergesort(nums, left, right):
if left >= right:
return 0
# 防止大数溢出
mid = left + (right - left) // 2
# 分治思想
cnt_l = mergesort(nums, left, mid)
cnt_r = mergesort(nums, mid + 1, right)
cnt_c = merge(nums, left, mid, right)

return cnt_l + cnt_r + cnt_c

def merge(nums, left, mid, right):
tmp, cnt = [], 0
i, j = left, mid + 1

while i <= mid and j <= right:
if nums[i] <= nums[j]:
tmp.append(nums[i])
i += 1
else:
tmp.append(nums[j])
j += 1
# 第二个序列插入时更新逆序数
cnt += (mid - i + 1)

if i <= mid:
tmp.extend(nums[i:mid+1])
else:
tmp.extend(nums[j:right+1])

nums[left:right+1] = tmp[:]
return cnt

return mergesort(nums, 0, len(nums)-1)

3. 堆排序

def heapify(a: list, n, i): 
largest = i
l = 2 * i + 1 # left = 2*i + 1
r = 2 * i + 2 # right = 2*i + 2

if l < n and a[i] < a[l]:
largest = l
if r < n and a[largest] < a[r]:
largest = r
if largest != i:
a[i],a[largest] = a[largest],a[i] # 交换
heapify(a, n, largest)

def heapSort(a: list):
n = len(a)
# Build a maxheap.
for i in range(n, -1, -1):
heapify(a, n, i)
# 一个个交换元素
for k in range(n-1, 0, -1):
a[k], a[0] = a[0], a[k] # 交换
heapify(a, k, 0)

堆排序(使用heapq)

import heapq

def heapSort (a: list):
heapq.heapify(a)
res = [heapq.heappop(a) for _ in range(len(a))]
return res

eg. ​​剑指 Offer II 059. 数据流的第 K 大数值​

class KthLargest:

def __init__(self, k: int, nums: List[int]):
self.k = k
self.q = nums
heapq.heapify(self.q)

def add(self, val: int) -> int:
heapq.heappush(self.q, val)
while len(self.q) > self.k:
heapq.heappop(self.q)
return self.q[0]


# Your KthLargest object will be instantiated and called as such:
# obj = KthLargest(k, nums)
# param_1 = obj.add(val)

4. 其他

​剑指 Offer II 075. 数组相对排序​

class Solution:
def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
n = max(arr1)
freq = [0] * (n+1)
for i in arr1:
freq[i] += 1
res = list()
for x in arr2:
res.extend([x] * freq[x])
freq[x] = 0
for x in range(n+1):
if freq[x] > 0: res.extend([x] * freq[x])
return res