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

今天是学习的算法的第三天内容为归并排序,今天难度比昨天更为上升,坚持就是胜利。

归并排序:

思想:

现将一个个数组分为两个子数组。然后递归的将数组进行排序,并将已排序的子数组合并成一个大的有序数组,直到合并为1个完整的数组。

事例:

有个数组[2,7,3,9,1,6,4,5]

先将数组分为两部分也就是:

[2,7,3,9]和[1,6,4,5]

然后再进行分割。

分为[2,7],[3,9],[1,6],[4,5]。

然后再不断进行分割。

接下来,归并排序开始合并这些有序的子数组。它总是从最小的子数组(即长度为1的数组)开始,逐步向上合并成更大的有序数组。在这个例子中,合并过程将如下进行:

  1. 合并 [2] 和 [7] 得到 [2, 7]
  2. 合并 [3] 和 [9] 得到 [3, 9]
  3. 合并 [1] 和 [6] 得到 [1, 6]
  4. 合并 [4] 和 [5] 得到 [4, 5]

然后,继续合并这些长度为2的有序数组:

  1. 合并 [2, 7] 和 [3, 9] 得到 [2, 3, 7, 9]
  2. 合并 [1, 6] 和 [4, 5] 得到 [1, 4, 5, 6]

最后,合并 [2, 3, 7, 9] 和 [1, 4, 5, 6] 得到完全排序的数组 [1, 2, 3, 4, 5, 6, 7, 9]

python代码如下:
n=int(input())#多少数字
a=list(map(int,input().split()))
def merge(leftlist,rightlist):
    newlist = []
    while len(leftlist)!=0 and len(rightlist)!=0:
        if leftlist[0]<rightlist[0]:
            newlist.append(leftlist.pop(0))#哪个数字更小就把哪个数字放入新列表当中。
        else:
            newlist.append(rightlist.pop(0))
    newlist.extend(leftlist)#两个列表当中必定有一个列表为空列表一个列表只剩一个数字。
    newlist.extend(rightlist)
    return newlist
def mergesort(a):
    if len(a)<2:
        return a
    mid=len(a)//2
    leftlist=mergesort(a[:mid])
    rightlist=mergesort(a[mid:])
    return merge(leftlist,rightlist)#不断地递归
print(mergesort(a))

注意归并排序有个小细节

print(mergesort(a))
//改成
mergesort(a)
print(a)

这样的结果是不一样的,归并排序不是一个原地排序算法。它使用额外的空间来创建和合并子列表。因此归并排序不是在原来的列表中修改的,他是新建了一个列表,也就是上面代码的newlist。

所以直接输出print(a)的话结果是错误的。

c++代码如下:
using namespace std;
const int N = 1e5 + 1;
int a[N];
// 合并两个已排序的部分到newlist数组,然后复制回a数组
void merge(int a[], int left, int mid, int right) {
    int n1 = mid - left + 1;
    int n2 = right - mid;
    int L[n1], R[n2], *newlist = new int[n1 + n2]; // 创建动态数组以避免局部变量作用域问题
    
    // 拷贝数据到临时数组
    for (int i = 0; i < n1; i++)
        L[i] = a[left + i];
    for (int j = 0; j < n2; j++)
        R[j] = a[mid + 1 + j];
    
    // 合并临时数组到newlist
    int i = 0, j = 0, k = 0;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            newlist[k++] = L[i++];
        } else {
            newlist[k++] = R[j++];
        }
    }
    // 拷贝剩余的L或R中的元素
    while (i < n1) {
        newlist[k++] = L[i++];
    }
    while (j < n2) {
        newlist[k++] = R[j++];
    }
    
    // 复制newlist到a数组
    for (int i = 0; i < n1 + n2; i++) {
        a[left + i] = newlist[i];
    }
}
// 归并排序的主函数
void mergeSort(int a[], int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2;
        mergeSort(a, left, mid);
        mergeSort(a, mid + 1, right);
        merge(a, left, mid, right); 
    }
}
int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    mergeSort(a, 0, n - 1);
    for (int i = 0; i < n; i++) {
        cout << a[i] << " ";
    }
    return 0;
}

c++的归并排序有多种写法,这里只提供一种。

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

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值