C++ L2-4排序算法

91 阅读3分钟

📌 1. 插入排序(斗地主摸牌)

image.png

  • 这个算法模拟的是“打扑克摸牌”的过程:

    • 左边的牌是有序的(已经排好)
    • 右边的牌是待插入的(还没摸)
    • 每次“摸到”一张牌(key),就往左边插入到合适的位置。
void insert_sort(int a[],int n){
	for(int i=2;i<=n;i++){
		int key=a[i];  //key 表示“当前摸到的这张牌”
		int j=i-1; // j 指向手里排好序的那一部分的最后一张牌
		//通过他的位置来算,而不是通过值去比较
		//1号-j号 是已经排好的
		//j+1号 - n号是需要排的
		 // 向左寻找合适的位置插入key
        // 只要 j 没越界,并且手里的牌比 key 大,就把牌往后挪
		while(j>=1 && a[j]>key){
			a[j+1]=a[j];// 把较大的牌往右移,为 key 腾出位置
			j--;   // 继续向左看下一张牌
		}
		 // 当找到不大于 key 的牌后,把 key 插入到它右边(j+1 位置)
		a[j+1]=key;  
	}
} 

📌 举个例子:

假设你现在要排序这个数组:

ini
复制编辑
a = [3, 5, 2]

执行到第2轮(i=2)时:

  • key = 2
  • j = 1,a[j] = 5,比2大 → 往后移动
  • j = 0,a[j] = 3,比2大 → 再往后移动
  • j = -1 ❗️❗️此时不能再访问 a[j] 了!

所以 j >= 0 的存在就是为了防止访问越界。

📌 2. 选择排序(找到最小的元素,将其放入已经排序的区间)

//选择排序 
void select_sort(int a[],int n){
	for(int i=1;i<=n;i++){
		int min_index=i;
		for(int j=i+1;j<=n;j++){
			if(a[min_index]>a[j]){
				min_index=j;
			}
		}
		//交换
		swap(a[min_index],a[i]);
	} 
}

📌 3. 冒泡排序(两两相互比较,谁大谁往后滚)

// 冒泡排序
void bubble_sort(int a[],int n){
	for(int i=1;i<=n-1;i++){
		for(int j=1;j<=n-i;j++){
			if(a[j]>a[j+1]){
				swap(a[j],a[j+1]);
			}
		} 
	}
}
  • 最好情况下O(n) 最坏情况O(n平方)
  • 适合有序度>逆序度的方法
  • 借助一个变量,flag ,检测有没有发生交换
  • 稳定性(稳定) image.png

📌 4. 计数排序(单独开一个数组)

image.png

  • 典型的空间换时间
  • 先得到这个数组中数据的最大值是多少,这样可以决定要开多大的计数数组
  • 存的这个数字当做新计数数组的编号 image.png
  • 如何保证计数排序的稳定性
  • 举个例子,这次考试后,老师要对大家的成绩进行排名。
  • 如果想实现想通数字的 前后排名的话,需要结合前缀和,每次拿一个数,对应位置的前缀和要-1,方便获取另一个数据的顺序

image.png

image.png

image.png

image.png

image.png

📌 5. 快速排序(比张三高的站右边,比张三矮的站左边)

  • 排序的本质是降低逆序度,提升有序度,直到达到满有序度的过程 image.png · 比张三高的站右边,比张三矮的站左边 一直重复就可以排好,分为左部分右半部分

image.png

image.png

image.png

📌 6. 归并排序(回家做作业,把作业分3类,语文数学英语)

  • 分治的思想
  • 将数列划分为2部分,找到最中间位置
  • 递归地分别对两个子序列进行归并排序
  • 合并两个子序列 image.png
  • 归并排序实例演示 image.png

image.png