- 比较类排序:
通过比较来决定元素间的相对次序,由于其时间复杂度不能突破
O(nlogn),因此也称为非线性时间比较类排序。 - 非比较类排序:
不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时
间下界,以线性时间运行,因此也称为线性时间非比较类排序
初级排序 - O(n^2)
- 选择排序(Selection Sort)
每次找最小值,然后放到待排序数组的起始位置。
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for(var i = 0; i < len - 1; i++) {
minIndex = i;
for(var j = i + 1; j < len; j++) {
if(arr[j] < arr[minIndex]) { // 寻找最小的数
minIndex = j; // 将最小数的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
struct SelectionSort {
func selectionSort(_ nums: [Int]) -> [Int] {
var nums = nums
_selectionSort(&nums)
return nums
}
func _selectionSort(_ nums: inout [Int]) {
for i in 0..<nums.count {
var minIndex = i
for j in i + 1..<nums.count {
if nums[minIndex] > nums[j] {
minIndex = j
}
}
if minIndex != i {
(nums[minIndex], nums[i]) = (nums[i], nums[minIndex])
}
}
}
}
- 插入排序(Insertion Sort)
从前到后逐步构建有序序列;对于未排序数据,在已排序序列中从后
向前扫描,找到相应位置并插入。
function insertionSort(arr) {
var len = arr.length;
var preIndex, current;
for(var i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i];
while(preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex];
preIndex--;
}
arr[preIndex + 1] = current;
}
return arr;
}
class InsertionSort {
func insertionSort(_ nums: [Int]) -> [Int] {
var nums = nums
self._insertionSort(&nums)
return nums
}
func _insertionSort(_ nums: inout [Int]) {
for i in stride(from: 1, to: nums.count, by: 1) {
let temp = nums[i]
var j = i - 1
while j >= 0 && nums[j] > temp {
nums[j + 1] = nums[j]
j -= 1
}
nums[j + 1] = temp
}
}
func _insertionSort2(_ nums: inout [Int]) {
for i in stride(from: 1, to: nums.count, by: 1) {
var j = i - 1
while j > 0 && nums[j] < nums[j - 1] {
(nums[j], nums[j - 1]) = (nums[j - 1], nums[j])
j -= 1
}
}
}
}
- 冒泡排序(Bubble Sort)
嵌套循环,每次查看相邻的元素如果逆序,则交换。
function bubbleSort(arr) {
var len = arr.length;
for(var i = 0; i < len - 1; i++) {
for(varj = 0; j < len - 1 - i; j++) {
if(arr[j] > arr[j+1]) { // 相邻元素两两对比
var temp = arr[j+1]; // 元素交换
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
class BubbleSort {
func bubbleSort(_ nums: [Int]) -> [Int] {
var nums = nums
self._bubbleSort2(&nums)
// self._bubbleSort(&nums)
return nums
}
func _bubbleSort(_ nums: inout [Int]) {
for i in 0..<nums.count {
var flag = false
// 将最小的放在了最左边
for j in stride(from: nums.count - 2, through: i, by: -1) {
if nums[j] > nums[j + 1] {
swap(&nums, i: j, j: j + 1)
flag = true
}
}
if flag == false {
break
}
}
}
// 利用异或交换
func swap(_ nums: inout [Int], i: Int, j: Int) {
if i == j {return}
nums[i] ^= nums[j];
nums[j] ^= nums[i];
nums[i] ^= nums[j];
}
func _bubbleSort2(_ nums: inout [Int]) {
for i in 0..<nums.count {
var flag = false
// 将最大的放到最右边
for j in 0..<nums.count - i - 1 {
if nums[j] > nums[j + 1] {
// 利用元祖交换
(nums[j], nums[j + 1]) = (nums[j + 1], nums[j])
flag = true
}
}
if flag == false {
break
}
}
}
}
高级排序 - O(N*LogN)
• 快速排序(Quick Sort)
数组取标杆 pivot,将小元素放 pivot左边,大元素放右侧,然后依次
对右边和右边的子数组继续快排;以达到整个序列有序
快排代码 - Java
// 调用方式:quickSort(a, 0, a.length-1)
public static void quickSort(int[] array, int begin, int end) {
if (end <= begin) return;
int pivot = partition(array, begin, end);
quickSort(array, begin, pivot - 1);
quickSort(array, pivot + 1, end);
}
static int partition(int[] a, int begin, int end) {
// pivot: 标杆位置,counter: ⼩于pivot的元素的个数
int pivot = end, counter = begin;
for (int i = begin; i < end; i++) {
if (a[i] < a[pivot]) {
int temp = a[counter]; a[counter] = a[i]; a[i] = temp;
counter++;
}
}
int temp = a[pivot]; a[pivot] = a[counter]; a[counter] = temp;
return counter;
}
//C/C++
int random_partition(vector<int>& nums, int l, intr) {
int random_pivot_index = rand() % (r - l +1) + l; //随机选择pivot
int pivot = nums[random_pivot_index];
swap(nums[random_pivot_index], nums[r]);
int i = l - 1;
for (int j=l; j<r; j++) {
if (nums[j] < pivot) {
i++;
swap(nums[i], nums[j]);
}
}
int pivot_index = i + 1;
swap(nums[pivot_index], nums[r]);
return pivot_index;
}
void random_quicksort(vector<int>& nums, int l, int r) {
if (l < r) {
int pivot_index = random_partition(nums, l, r);
random_quicksort(nums, l, pivot_index-1);
random_quicksort(nums, pivot_index+1, r);
}
}
def quick_sort(begin, end, nums):
if begin >= end:
return
pivot_index = partition(begin, end, nums)
quick_sort(begin, pivot_index-1, nums)
quick_sort(pivot_index+1, end, nums)
def partition(begin, end, nums):
pivot = nums[begin]
mark = begin
for i in range(begin+1, end+1):
if nums[i] < pivot:
mark +=1
nums[mark], nums[i] = nums[i], nums[mark]
nums[begin], nums[mark] = nums[mark], nums[begin]
return mark
// JavaScript
const quickSort = (nums, left, right) => {
if (nums.length <= 1) return nums
if (left < right) {
index = partition(nums, left, right)
quickSort(nums, left, index-1)
quickSort(nums, index+1, right)
}
}
const partition = (nums, left, right) => {
let pivot = left, index = left + 1
for (let i = index; i <= right; i++) {
if (nums[i] < nums[pivot]) {
[nums[i], nums[index]] = [nums[index], nums[i]]
index++
}
}
[nums[pivot], nums[index-1]] = [nums[index-1], nums[pivot]]
return index -1
}
class QuickSort {
func quickSort(_ arr: [Int]) -> [Int] {
var result = arr
// quickSort1(&result, 0, arr.count)
quickSort(&result, 0, arr.count - 1)
return result
}
private func quickSort(_ arr: inout [Int], _ start: Int, _ end: Int) {
if start == end {
return
}
let pivot = partitionByQuickSort(&arr, start, end)
quickSort(&arr, start, pivot - 1)
quickSort(&arr, pivot + 1, end)
}
private func partition1ByQuickSort(_ arr: inout [Int], _ start: Int, _ end: Int) -> Int {
var start = start, end = end
let temp = arr[start]
let preStart = start
// [3, 2, 1] => [1, 2, 3]
while start < end {
while start < end && arr[end] > temp {
end -= 1
}
while start < end && arr[start] < temp {
start += 1
}
(arr[start], arr[end]) = (arr[end], arr[start])
}
(arr[preStart], arr[start]) = (arr[start], arr[preStart])
return start
}
private func partitionByQuickSort(_ arr: inout [Int], _ start: Int, _ end: Int) -> Int {
//[ 2, 1]
let pivotElement = arr[end]
var i = start
for j in stride(from: start, to: end, by: 1) {
if arr[j] <= pivotElement {
(arr[i], arr[j]) = (arr[j], arr[i])
i += 1
}
}
(arr[i], arr[end]) = (arr[end], arr[i])
return i
}
private func quickSort1(_ arr: inout [Int], _ start: Int, _ end: Int) {
if end - start == 1 {
return
}
let mid = findPivotByQuickSort1(&arr, start, end)
quickSort1(&arr, start, mid)
quickSort1(&arr, mid + 1, end)
}
private func findPivotByQuickSort1(_ arr: inout [Int], _ start: Int, _ end: Int) -> Int {
let pivotElement = arr[start]
var begin = start
var over = end
while begin < over {
while begin < over {
if pivotElement < arr[over] {
over -= 1
}else {
arr[begin] = arr[over]
begin += 1
break
}
}
while begin < over {
if arr[begin] < pivotElement {
begin += 1
}else {
arr[over] = arr[begin]
over -= 1
break
}
}
}
arr[begin] = pivotElement
return begin
}
}
归并排序(Merge Sort)— 分治
1. 把长度为n的输入序列分成两个长度为n/2的子序列;
2. 对这两个子序列分别采用归并排序;
3. 将两个排序好的子序列合并成一个最终的排序序列。
归并排序代码 - Java
public static void mergeSort(int[] array, int left, int right) {
if (right <= left) return;
int mid = (left + right) >> 1; // (left + right) / 2
mergeSort(array, left, mid);
mergeSort(array, mid + 1, right);
merge(array, left, mid, right);
}
public static void merge(int[] arr, int left, int mid, int right) {
int[] temp = new int[right - left + 1]; // 中间数组
int i = left, j = mid + 1, k = 0;
while (i <= mid && j <= right) {
temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
}
while (i <= mid) temp[k++] = arr[i++];
while (j <= right) temp[k++] = arr[j++];
for (int p = 0; p < temp.length; p++) {
arr[left + p] = temp[p];
}
// 也可以⽤ System.arraycopy(a, start1, b, start2, length)
}
归并 和 快排 具有相似性,但步骤顺序相反
归并:先排序左右子数组,然后合并两个有序子数组
快排:先调配出左右子数组,然后对于左右子数组进行排序
堆排序(Heap Sort) — 堆插入 O(logN),取最大/小值 O(1)
1. 数组元素依次建立小顶堆
2. 依次取堆顶元素,并删除
static void heapify(int[] array, int length, int i) {
int left = 2 * i + 1, right = 2 * i + 2;// 下标从0开始,如果下标从1开始,则为left = 2i, right = 2i + 1
int largest = i;
if (left < length && array[left] > array[largest]) {
largest = left;
}
if (right < length && array[right] > array[largest]) {
largest = right;
}
if (largest != i) {
int temp = array[i]; array[i] = array[largest]; array[largest] = temp;
heapify(array, length, largest);
}
}
public static void heapSort(int[] array) {
if (array.length == 0) return;
int length = array.length;
for (int i = length / 2-1; i >= 0; i-)
heapify(array, length, i); // 将数组变成堆,
for (int i = length - 1; i >= 0; i--) { // 从最后一个元素向前遍历,把堆顶元素依次取出来挪到最后面
int temp = array[0]; array[0] = array[i]; array[i] = temp;
heapify(array, i, 0); // 从array中依次取出最小的元素出来,放在数组最前面
}
}
#Python
def heapify(parent_index, length, nums):
temp = nums[parent_index]
child_index = 2*parent_index+1
while child_index < length:
if child_index+1 < length and nums[child_index+1] > nums[child_index]:
child_index = child_index+1
if temp > nums[child_index]:
break
nums[parent_index] = nums[child_index]
parent_index = child_index
child_index = 2*parent_index + 1
nums[parent_index] = temp
def heapsort(nums):
for i in range((len(nums)-2)//2, -1, -1):
heapify(i, len(nums), nums)
for j in range(len(nums)-1, 0, -1):
nums[j], nums[0] = nums[0], nums[j]
heapify(0, j, nums)