笔者这里在网上没有找到非常系统的适用于初学者提高技能的C&C++博客,因此在这里希望通过本人所学,为所有有志于学习了解一般计算机基础算法的同学提供自己的一点见解(也可作为acm的一个起步?)
主要有六讲的内容,这里是第一讲:包含
1. 基础算法:一系列排序算法
2. 数据结构:堆栈,链表 etc.
3. DP:
4. 贪心算法:
5. 图论初步及搜索算法
6. 一些补充
不定时更新,希望能对大家学习提供一定的帮助,如有不正确,可以留言指正,大概在更新期间会一直查看(最近会尽量做到1天1更)
O、C&C++入门
这里不对基础语法做更多的说明,我希望大家可以先尝试的去写代码,根据已经写好的代码理解。在具体不懂的地方查询和理解基础语法(baidu or chatGPT)
一、快速排序
主要思想: 分而治之
时间复杂度:O(n*lgn)
1.1 基本思路:
*我们都知道一个有序的队列,任意的一个子序列都必须是有序的,只需要让任意子序列有序,那么整体的队列都是有序的*
简而言之,只要使得划分出每一段,都是可以保证左边小于(大于)右边,就可以保证整个数列是从小到大(从大到小)的
这里我们举例:
对5个数字排序,31245,输出为从小到大排列:
第一步:比大小:在全段中找一个数字(比如第一个数字3)
第二步:做交换:规定一个左指针(从左到右扫描)指向最左端和一个右指针指向最右端(从右到左扫描),(在两个指针相遇前)若左指针指到不小于3的数字,则右指针开始扫描直到指到不大于3的数字,交换指针所指数字,重复(直到指针相遇)
3*1245(左指针指向3,右指针开始移动)
3*12*45(两指针未相遇,交换)
213**45(指针移动,相遇,下一步)
第三步:分开段,将213**45在3处分开,如下:21345 对每一段重复以上三步直到排序完成
全流程如下:
3*1245(左指针指向3,右指针开始移动)
3*12*45(两指针未相遇,交换)
213**45(指针移动,相遇,下一步)
进入分段递归
2*13(左指针指向2,右指针开始移动) 4*5(左指针指向4,右指针开始移动)
2*1*3(右指针指向1*,两指针未相遇交换) 4**5(指针相遇,分段)
1**23(指针移动相遇,分段) 4(单个数字返回) 5(单个数字返回)
1(单个数字返回)2(单个数字返回)3(单个数字返回)4(单个数字返回) 5(单个数字返回)
得到最终结果:12345
1.2 样例代码
#include<stdio.h>
#include<iostream>
using namespace std;
const int N = 1e+6;
int a[N];
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j), quick_sort(q, j + 1, r);
}
int main(){
int n;
cin>>n;
for(int i=1; i<=n; i++){
scanf("%d",&a[i]);
}
quick_sort(a,1,n);
for(int i=1; i<=n; i++){
cout<<a[i];
}
return 0;
}
1.3 强化训练
给n个数字组成的数组,请寻找其中第k个最大的数字。
输入:5 2
31245
输出:4
可以同样试一下如何找到第k个最小的数字
一些废话但是可能也许会很重要,如果我只需要输出第k个最大或者最小的数字而不要求你去完成整个数组排序呢?
尽可能时间复杂度低
去对应的分段里面寻找,最终答案如下:
#include<stdio.h>
#include<iostream>
using namespace std;
const int N = 1e+6;
int a[N];
void quick_sort_fink(int q[], int l, int r, int k)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
if (j-l+1 > k)
quick_sort(q, l, j, k)
else
quick_sort(q, j + 1, r, k-j+l-1);
}
二、归并排序
主要思想:递归
时间复杂度:O(n*logn)
*首先我们都知道一个有序的队列,任意的一个子序列都必须是有序的,那么相反的,通过若干个有序子序列顺序拼接的序列也一定是有序的;其次,两个有序序列合并时顺序是很好排的。*