初级排序和高级排序

在这里插入图片描述
十大经典排序算法(动图演示)

  1. 比较类排序:
    通过比较来决定元素间的相对次序,由于其时间复杂度不能突破
    O(nlogn),因此也称为非线性时间比较类排序。
  2. 非比较类排序:
    不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时
    间下界,以线性时间运行,因此也称为线性时间非比较类排序
初级排序 - O(n^2)
  1. 选择排序(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])
            }
        }
    }
}
  1. 插入排序(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
           }
       }
   }
}
  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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值