排序算法大总结(选择、冒泡、插入、归并、快排、堆排序)(附带C++参考代码)

目录

小总结

关于面试中排序算法常见的坑

工程上对排序的改进

各个排序的C++参考代码

1.选择排序

2.冒泡排序

3.插入排序

4.归并排序

5.快速排序

6.堆排序


  时间复杂度 额外空间复杂度 稳定性
选择排序 O(N²) O(1) ×
冒泡排序 O(N²) O(1)
插入排序 O(N²) O(1)
归并排序 O(N*logN) O(N)
快速排序 O(N*logN) O(logN) ×
堆排序 O(N*logN) O(1) ×

小总结

  1. 一般的排序算法选择快速排序,有两个原因:1.快排的时间复杂度较优 2.实验结果证明,快排的时间复杂度的表达式中常数项是最小的(常数时间最小)。
  2. 需要稳定性时选择归并排序。
  3. 额外空间有限制时选择堆排序。

关于面试中排序算法常见的坑

  1. 归并排序的额外空间复杂度可以变成0(1),但是非常难,不需要掌握,有兴趣可以搜“归并排序内部缓存法”
  2. “原地归并排序”的帖子都是垃圾,会让归并排序的时间复杂度变成0(N^2)3,快速排序可以做到稳定性问题,但是非常难,不需要掌握,可以搜“01stable sort”
  3. 所有的改进都不重要,因为目前没有找到时间复杂度O(N*logN),额外空间复杂度0(1),又稳定的排序。
  4. 有一道题目,是奇数放在数组左边,偶数放在数组右边,还要求原始的相对次序不变,碰到这个问题,可以怼面试官。

工程上对排序的改进

  1. 充分利用O(N*logN)和O(N²)排序各自的优势
  2. 稳定性的考虑
     

各个排序的C++参考代码

1.选择排序

void selection_sort(int* a, int num)
{
    for (int i = 0; i < num - 1; ++i)
    {
        for (int j = i + 1; j < num; ++j)
        {
            if (a[i] > a[j])
            {
                a[i] = a[i] ^ a[j];
                a[j] = a[i] ^ a[j];
                a[i] = a[i] ^ a[j];
            }
        }
    }
}

2.冒泡排序

void bubble_sort(int* a, int num)
{
    for (int i = 0; i < num - 1; ++i)
    {
        for (int j = 0; j < num - i - 1; ++j)
        {
            if (a[j] > a[j + 1])
            {
                std::swap(a[j], a[j + 1]);
            }
        }
    }
}

3.插入排序

​void insertion_sort(int* a, int num)
{
    for (int i = 1; i < num; ++i)
    {
        int key = a[i];
        int j = i - 1;
 
        while (j >= 0 && a[j] > key)
        {
            a[j + 1] = a[j];
            j--;
        }
 
        a[j + 1] = key;
    }
}

4.归并排序

#include
#include
void merge(std::vector& arr, int L, int mid, int R);
void mergeSort(std::vector& arr, int L, int R) 
{
    if (L == R) {
        return;
    }
    int mid = L + ((R - L) >> 1);
 
    mergeSort(arr, L, mid);
    mergeSort(arr, mid + 1, R);
    merge(arr, L, mid, R);
}
void merge(std::vector& arr, int L, int mid, int R)
{
    std::vector help(R - L + 1);
    int n1 = L;
    int n2 = mid + 1;
    int i = 0;
 
    while (n1 <= mid && n2 <= R)
    {
        help[i++] = arr[n1] < arr[n2] ? arr[n1++] : arr[n2++];
    }
    while (n1 <= mid)
    {
        help[i++] = arr[n1++];
    }
    while (n2 <= R)
    {
        help[i++] = arr[n2++];
    }
    for (i = L; i <= R; i++)
    {
        arr[i] = help[i - L];
    }
 
}
int main() {
    std::vector arr = { 12, 11, 13, 5, 6, 7,5,1,2,3,8,2,35,3 };
    int n = (int)arr.size();
 
    mergeSort(arr, 0, n - 1);
 
    std::cout << "排序后的数组:";
    for (int i = 0; i < n; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
 
    return 0;
}

5.快速排序

int* partition(int* arr, int L, int R)
{
	int less = L - 1;
	int more = R;
	int* a = new int[2];
	while (L < more){
		if (arr[L] < arr[R]){
			std::swap(arr[++less], arr[L++]);
		}
		else if (arr[L] > arr[R]){
			std::swap(arr[--more], arr[L]);
		}
		else{
			L++;
		}
	}
	std::swap(arr[more], arr[R]);
	a[0] = less + 1;
	a[1] = more;
	return a;
}
void quickSort(int* arr, int L, int R)
{
	if (L < R) {
		std::swap(arr[rand() % (R - L + 1) + L], arr[R]);
		int* a = partition(arr, L, R);
		quickSort(arr, L, a[0] - 1);
		quickSort(arr, a[1] + 1, R);
	}
}

6.堆排序

​
void heapify(int* arr, int index, int heapsize)
{
	int left = index * 2 + 1;
	int largest;
	while (left < heapsize)
	{
		largest = left + 1 < heapsize && arr[left + 1] > arr[left] ? left + 1 : left;
		largest = arr[largest] > arr[index] ? largest : index;
		if (largest == index)
		{
			break;
		}
		std::swap(arr[largest], arr[index]);
		index = largest;
		left = index * 2 + 1;
	}
	
}
 
void heapSort(int arr[], int size)
{
	for (int i = size / 2 - 1; i >= 0; i--)
	{
		heapify(arr, i, size);
	}
	for (int i = size - 1; i >= 1; i--)
	{
		std::swap(arr[0], arr[i]);        
		heapify(arr, 0, i);              
	}
}

总结不易,请点赞收藏。(部分内容来源于左神数据机构与算法)。

你可能感兴趣的:(算法,数据结构,排序算法)