手撸快排居然失败,可怕。准备好这几种排序算法,面试不心慌。
3.1 排序
3.1.0 堆排序
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
nums.insert(nums.begin(), 0);
heapSort(nums, nums.size()-1);
vector<int> res(nums.begin()+1, nums.end());
return res;
}
void heapSort(vector<int>& a, int len) {
buildHeap(a, len); // 初始建堆
for (int i = len; i > 1; i--) { // n-1趟的交换和建堆过程
swap(a[i], a[1]); // 和堆底元素交换
adjustDown(a, 1, i - 1); // 把剩余的i-1个元素整理成堆
}
}
void adjustDown(vector<int>& a, int k, int len) {
a[0] = a[k]; // a[0]暂存
for (int i = 2 * k; i <= len; i *= 2) { // 沿key较大的子节点向下筛选
if (i < len && a[i] < a[i+1]) { // 小顶堆只需要需改 a[i] > a[i+1] 以及下面结束 a[0] <= a[i]即可
i++; // 取key较大的子节点下标
}
if (a[0] >= a[i]) {
break; // 筛选结束
} else {
a[k] = a[i]; // 将A[i]调整到双亲节点上
k = i; // 修改k值,以便继续向下筛选
}
}
a[k] = a[0]; // 将被筛选的节点的值放入最终位置
}
void buildHeap(vector<int>& a, int len) {
for (int i = len / 2; i > 0; i--) { // 从i = n/2 到 1 反复调整堆
adjustDown(a, i, len);
}
}
};
3.1.1 归并排序 √
devide & conquer的思想。 mergeSort就是devide, merge就是conquer。
func sortArray(nums []int) []int {
mergeSort(nums, 0, len(nums)-1)
return nums
}
func mergeSort(nums []int, p, r int) {
if p < r {
mid := p + (r-p)/2
mergeSort(nums, p, mid)
mergeSort(nums, mid+1, r)
merge(nums, p, mid, r)
}
}
func merge(nums []int, p, mid, r int) {
a := make([]int, mid-p+1)
b := make([]int, r-mid)
copy(a, nums[p:mid+1])
copy(b, nums[mid+1:r+1])
i, j := 0, 0
idx := p
for i < len(a) && j < len(b) {
if a[i] < b[j] {
nums[idx] = a[i]
i++
}else {
nums[idx] = b[j]
j++
}
idx++
}
for i < len(a) {
nums[idx] = a[i]
i++
idx++
}
for j < len(b) {
nums[idx] = b[j]
j++
idx++
}
}
3.1.2 快速排序 √
快速排序分三个阶段
1 写出最基本的快速排序 2-3分钟 pivot = a[r];
2 使用median对快速排序的pivot进行优化 pivot = median3(); 1-2min
3 使用cutoff和insertionSort对快速排序进行优化 if (p + cutoff < r){}else{}; 2-3min
- 快排的基本版本 5min
func sortArray(nums []int) []int {
quickSort(&nums, 0, len(nums)-1)
return nums
}
func quickSort(a *[]int, p, r int) {
if p < r {
q := partition(a, p, r)
quickSort(a, p, q-1)
quickSort(a, q+1, r)
}
}
func partition(a *[]int, p, r int) int {
pivot := (*a)[r]
i := p-1
for j := p; j < r; j++ {
if (*a)[j] <= pivot {
i++
swap(a, i, j)
}
}
swap(a, i+1, r)
return i+1
}
func swap(a []int, i, j int){
a[i], a[j] = a[j], a[i]
}
- 快排的进阶版本2.0
pivot := median3(*a, p, r)
替换pivot := (*a)[r]
func median3(a []int, p, r int) int {
q := p + (r-p)/2
if a[p] > a[q] {
swap(a, p, q)
}
if a[q] > a[r] {
swap(a, q, r)
}
if a[p] > a[q] {
swap(a, p, q)
}
swap(a, q, r)
return a[r]
}
- 快排的进阶版本3.0
添加cutoff
小于cutoff
用插入排序
func insertionSort(a []int, p, r int){
for i := p+1; i <= r; i++ {
tmp := a[i]
j := i-1
for j >= p && tmp < (*a)[j] {
a[j+1] = a[j]
j--
}
a[j+1] = tmp
}
}
class Solution {
public int[] sortArray(int[] nums) {
quickSort(nums, 0, nums.length-1);
return nums;
}
private static int CUTOFF = 10;
public static void quickSort(int[] a, int p, int r){
if(p + CUTOFF < r){
int q = partition(a, p, r);
quickSort(a, p, q-1);
quickSort(a, q+1, r);
}else{
insertionSort(a, p, r);
}
}
public static int partition(int[] a, int p, int r){
int pivot = median3(a, p, r);
int i = p-1;
for(int j = p; j < r; j++){
if( a[j] <= pivot) { // 注意这个等于号
i++;
swap(a, i, j);
}
}
swap(a, i+1, r); // 因为在median中将pivot放在最后一位了 此处的swap一定要和median统一 因为是逐步改进而来的 所以pivot在median中的位置放最后
return i+1;
}
public static void swap(int[] a, int p, int r){
int tmp = a[p];
a[p] = a[r];
a[r] = tmp;
}
public static int median3(int[] a, int p, int r){
int mid = p + (r-p)/2;
if(a[mid] < a[p]){
swap(a, p, mid);
}
if(a[r] < a[p]){
swap(a, p, r);
}
if(a[r] < a[mid]){
swap(a, mid, r);
}
swap(a, mid, r);
return a[r];
}
public static void insertionSort(int[] a, int p, int r){
for(int i = p+1; i <= r; i++){
int tmp = a[i];
int j = i - 1;
while(j >= p && a[j] > tmp){
a[j+1] = a[j];
j--;
}
a[j+1] = tmp;
}
}
}
3.1.3 插入排序 √
将待排序序列分为已排序和未排序两个部分。初始状态,已排序序列只包含第一个元素,此后将未排序的元素逐一(key)插入到已排序元素中。
func insertionSort(nums []int) []int {
for i := 1; i < len(nums); i++ {
tmp := nums[i]
j := i-1
for j >= 0 && tmp <= nums[j] {
nums[j+1] = nums[j]
j--
}
nums[j+1] = tmp
}
return nums
}
3.1.4 选择排序 √
它的工作原理是每一次从待排序的数据元素中选出最小的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
func selectionSort(nums []int) []int {
for i := 0; i < len(nums); i++ {
min := i
for j := i+1; j < len(nums); j++ {
if nums[j] < nums[min] {
min = j
}
}
nums[i], nums[min] = nums[min], nums[i]
}
return nums
}