从零开始备战蓝桥杯——一天一个小算法第二天(排序篇)

今天我们的算法内容为插入排序和快速排序,难度比昨天上升了一点。

插入排序

思想:

将待排序的元素逐渐插入到已排序序列的合适位置中,有序序列不断扩大,直至全部。

将第一个元素视为已排序,然后从第二个元素开始往后遍历每个元素。

就如抓扑克牌一般,开局有一张牌,随后再摸一张,比第一张牌大放后面,比一张牌小放前面。

之后再摸一张牌,再与这原来的两张牌进行比较大小的,不断进行以上操作,最后牌摸完同时大小也拍好了。

事例:

当摸第i张牌时候,[0,i-1]的牌已经是排好顺序了的。

我们只需要将第i张牌与[0,i-1]里的牌进行大小比较,再进行插入即可,而其中[0,i-1]的牌是进行从后往前遍历的。

最后即可得到一个有序的牌库,也就是有序数组。

时间复杂度为O(n^2) 空间复杂度为O(1)

python代码如下:
n=int(input())#多少数字
a=list(map(int,input().split()))
for i in range(1,n):
    number=a[i]
    idx=0#插入位置
    for j in range(i-1,-1,-1):#从后往前遍历已经分类好了数字。
        if a[j]>number:
            a[j+1]=a[j]#a[j+1]原来是number的位置因为number比a[j]小所以向前一位,而a[j+1]大小就成了a[j]
        else: #也就是number>a[j]的情况。
            idx=j+1 #这个时候也就确定好了插入位置,插入的位置就是j+1这个位置
            break#前面的数字不用再判断,跳出循环
    a[idx]=number
print(a)

除了用for循环写也可以用while来写。 

n = int(input())
a = list(map(int, input().split()))
for i in range(1, n):
    number = a[i]
    idx = i - 1 定义插入位置
    while idx >= 0 and a[idx] > number:#只有当两个条件都满足时候才进行while循环
        a[idx + 1] = a[idx]
        idx -= 1
    a[idx + 1] = number#当while结束时idx+1的位置就是插入的位置
print(a)
c++代码如下:
#include <iostream>
using namespace std;
const int N = 1e3 + 1;
int a[N];
int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) cin >> a[i];
    for (int i = 1; i < n; i++) {
        int number = a[i];//定义插入的数字
        int j = i - 1;//插入位置
        while (j >= 0 && a[j] > number) //当a[j]<number时候停止循环也就是number所需要插入的位置
        {
            a[j + 1] = a[j];
            j--;//每小于一次j插入的位置-1
        }
        a[j + 1] = number;
    }
    for (int i = 0; i < n; i++) cout << a[i] << " ";
    return 0;
}

你已经学会插入排序了,请你用插入排序试一下解决排序问题吧。

插入排序题icon-default.png?t=N7T8https://www.lanqiao.cn/problems/298/learning/?page=1&first_category_id=1&name=%E6%8E%92%E5%BA%8F

快速排序

思想:

快速排序之所以叫快速排序就是因为它比较快。

它最重要的思想是递归和分治。

还是用一堆扑克牌举例,与上次不一样的是,你没有边抽边排序,你是抽完以后再排序。

抽完以后你看着手中一堆的扑克牌,先选择一张牌,令它为基准值。

然后你将扑克牌分为三部分,一部分为大于这个牌的数字,另一部分是小于这个牌的数字,还有一部分就是它自己。

在之后小于它的牌,和大于它的牌再不断进行以上操作递归。

事例:

假设有个数组[4,1,5,7,9,8,3]

为了方便我们就设刚开始的基准值为4,基准值的下标为left,你也可以随便设为这个数组的某个数字。

刚开始存放小于等于基准值的数字的下标为idx=left+1。

开始遍历数组。

先遍历到1,因为1刚好是小于基准值的数字,所以之后比基准值小的数字要放在idx+1处。

5,7,9,8都大于4所以就放在原位置。

因为3小于四所以要进行换位,将3移动到idx的位置而idx上的数字移动到3的数字,随后idx+1再往后判断有没有数字小于基准值4进行换位。

最后我们产生了新的数组[4,1,3,5,7,9,8]。

而所有小于等于基准值的数字都放在[left+1,idx-1]处

随后我们再将基准值的数字与3进行换位,(为什么不是将小于基准值的数字插入前面呢,因为这样的时间复杂度太高了。)就是a[left],a[idx-1]=a[idx-1],a[left]。

最后就产生了新的数组[3,1,4,5,7,9,8]。

将大于基准值和小于基准值的数分开,而之后我们只需要进行不断的分治与递归即可。

python代码如下:
n = int(input())
a = list(map(int, input().split()))
def partition(a, left, right):
    idx = left + 1  # 从left的下一个位置开始遍历
    for i in range(left + 1, right + 1):
        # 如果当前元素小于等于基准值,则交换
        if a[i] <= a[left]:
            a[idx], a[i] = a[i], a[idx]
            idx += 1
            # 将基准值放到中间(所有小于等于它的值的右边)
    a[left], a[idx - 1] = a[idx - 1], a[left]
    # 返回基准值的最终位置(也是左右子数组的分界点)
    return idx - 1
def quicksort(a, left, right):
    if left < right:
        mid = partition(a, left, right)  # 获取基准值的下标
        quicksort(a, left, mid - 1)  # 对基准值左边的子数组进行排序,递归
        quicksort(a, mid + 1, right)  # 对基准值右边的子数组进行排序,递归
quicksort(a, 0, n - 1)
print(*a)
c++算法如下
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 1;
int a[N];
int partition(int a[], int left, int right) {
    int idx = left+1; // 从left+1的位置开始遍历
    for (int i = left + 1; i <= right; i++) {
        if (a[i] < a[left]) {
            swap(a[idx], a[i]);
            idx++;
        }
    }
    swap(a[left], a[idx-1]);
    return idx-1;//返回下标为idx-1
}
void quicksort(int a[], int left, int right) {
    if (left < right) {
        int mid = partition(a, left, right);//找出基准值的下标
        quicksort(a, left, mid - 1);//左边的数进行以上的递归
        quicksort(a, mid + 1, right);//右边的数进行以上的递归
    }
}
int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    quicksort(a, 0, n - 1);
    for (int i = 0; i < n; i++) {
        cout << a[i] << " ";
    }
    return 0;
}

学会了的可以去试一下这道题,你也可以用之前学的选择排序,插入排序试一下,你会发现不行。

蓝桥账户中心

OK今天的算法内容就到这了,今天是学算法的第二天,算法最重要的内容是要多练,你的放弃可能会成就更多的人,我们明天再见。

  • 36
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是刷算法备战蓝桥杯的一些建议和步骤: 1. 熟悉蓝桥杯的考试内容和题型。了解蓝桥杯的考试规则、题目类型和难度分布,可以从蓝桥杯官方网站或者相关的参考资料中获取这些信息。 2. 学习基础知识。蓝桥杯的题目通常涉及到算法数据结构的基础知识,例如数组、链表、栈、队列、树、图、排序算法、查找算法等。建议先学习这些基础知识,掌握它们的原理和常见的应用场景。 3. 刷题练习。通过刷题来提高算法和编程能力是非常重要的。可以选择一些经典的算法题目进行练习,例如ACM/ICPC、LeetCode、牛客网等平台上的题目。刷题的过程中要注重理解题目的要求,分析问题的解决思路,编写代码实现解决方案,并进行调试和测试。 4. 参加模拟考试。蓝桥杯的模拟考试可以帮助你熟悉考试的流程和题目类型,也可以检验你的学习成果。参加模拟考试后,可以分析自己的得分情况,找出自己的不足之处,并进行针对性的复习和提高。 5. 学习优秀的解题思路和代码。在刷题的过程中,可以学习一些优秀的解题思路和代码,了解不同的解题方法和技巧。可以通过查阅相关的参考书籍、博客、论坛等获取这些信息。 6. 多做实战训练。除了刷题,还可以参加一些实战训练,例如参加ACM/ICPC比赛、编程竞赛等。这些实战训练可以提高你的编程能力和解题速度,也可以锻炼你的团队合作和应对压力的能力。 7. 多与他人交流和讨论。与他人交流和讨论可以帮助你更好地理解和掌握算法和编程知识。可以加入一些算法学习群组、论坛或者参加一些线下的学习活动,与其他学习者一起交流和分享经验。 8. 坚持练习和复习。刷算法题是一个长期的过程,需要坚持不懈地练习和复习。每天保持一定的学习时间,不断积累和提高自己的算法和编程能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值