尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

第 11 章 排序

第 11 章 排序 https://www.luogu.com.cn/problem/P1177https://www.luogu.com.cn/problem/P1177# P1177 【模板】排序## 题目描述将读入的 $N$ 个数从小到大排序后输出。## 输入格式第一行为一个正整数 $N$。第二行包含 $N$ 个空格隔开的正整数 $a_i$为你需要进行排序的数。## 输出格式将给定的 $N$ 个数从小到大输出数之间空格隔开。## 输入输出样例 #1### 输入 #154 2 4 5 1### 输出 #11 2 4 4 5## 说明/提示对于 $20\%$ 的数据有 $1 \leq N \leq 10^3$对于 $100\%$ 的数据有 $1 \leq N \leq 10^5$$1 \le a_i \le 10^9$。1.插入排序1算法思想待排序元素插入已排序序列中2代码加优化#includeiostream using namespace std; typedef long long ll; const ll N 1e56; ll a[N]; int main(){ ll n; cin n; for(ll i 1;i n;i) cin a[i]; for(ll i 2;in;i){ if(a[i] a[i-1]) continue; ll t a[i]; for(ll j 1;ji;j){ if(a[i]a[j]){ for(ll k i-1;kj;k--){ a[k1]a[k]; } a[j] t; break; } } } for(ll i 1;i n;i) cout a[i] ; }此时代码时间复杂度O(n^3),时间复杂度过高注意到第二个for循环的作用是定t的位置第三个for循环是移位那么可不可以直接在移步中定位呢当然可以#includeiostream using namespace std; typedef long long ll; const ll N 1e56; ll a[N]; int main(){ ll n; cin n; for(ll i 1;i n;i) cin a[i]; for(ll i 2;in;i){ ll t a[i]; ll j i-1; while(j1 a[j]t){ a[j1] a[j]; j--; } a[j1] t; } for(ll i 1;i n;i) cout a[i] ; }这题不是ac,是插入排序本身复杂但方法一定要掌握2选择排序1算法思想每次找到未排中最小的放有序序列后面2错误典例代码分析#includeiostream using namespace std; typedef long long ll; const ll N 1e56; ll a[N]; ll id 2; ll minn 1e9; int main(){ ll n; cin n; for(ll i 1;i n;i) cin a[i]; for(int i 1;i n;i){ for(int j n;ji;j--){ if(a[j] minn){ minn a[j]; id j; } } if(a[id]a[i]){ ll t a[i]; a[i] a[id]; a[id] t; } } for(ll i 1;i n;i) cout a[i] ; }错误点minn的作用是找到未排序列如果定义为全局变量那前面的都可以#includeiostream using namespace std; typedef long long ll; const ll N 1e56; ll a[N]; ll id 2; int main(){ ll n; cin n; for(ll i 1;i n;i) cin a[i]; for(int i 1;i n;i){ ll minn 1e9; for(int j n;ji;j--){ if(a[j] minn){ minn a[j]; id j; } } if(a[id]a[i]){ ll t a[i]; a[i] a[id]; a[id] t; } } for(ll i 1;i n;i) cout a[i] ; }那么有什么办法可以优化吗3优化1minn没有必要a[id]就可以搞定2第一层for循环不需要遍历n,因为最后一个数就一定有序3cppSTL库里有交换swap#includeiostream using namespace std; typedef long long ll; const ll N 1e56; ll a[N]; int main(){ ll n; cin n; for(ll i 1;i n;i) cin a[i]; for(int i 1;i n;i){ ll id i; for(int j n;ji;j--){ if(a[j] a[id]){ id j; } } swap(a[i],a[id]); } for(ll i 1;i n;i) cout a[i] ; }没错,他的复杂度更坏是铁钉钉的O(n^2)3,冒泡排序1算法思想执行n-1趟每趟从前往后比较未排序区间两相邻元素若逆序就交换每次在最后定下一个较大数#includeiostream using namespace std; typedef long long ll; const ll N 1e59; ll a[N]; int main(){ ll n; cin n; for(int i 1;i n;i) cin a[i]; for(ll i 1;i n;i){ for(int j 1;jn-i;j){ if(a[j]a[j1] ){ swap(a[j1],a[j]); } } } for(ll i 1;i n;i) cout a[i] ; }2优化优化一直接根据第几趟来定第二个循环边界#includeiostream using namespace std; typedef long long ll; const ll N 1e59; ll a[N]; int main(){ ll n; cin n; for(int i 1;i n;i) cin a[i]; for(ll i n;i 1;i--){ for(int j 1;ji;j){ if(a[j]a[j1] ){ swap(a[j1],a[j]); } } } for(ll i 1;i n;i) cout a[i] ; }优化二若某一趟操作中没有执行元素交换操作时证明已经有序-没有必要继续了#includeiostream using namespace std; typedef long long ll; const ll N 1e59; ll a[N]; int main(){ ll n; cin n; for(int i 1;i n;i) cin a[i]; for(ll i n;i 1;i--){ int front 0; for(int j 1;ji;j){ if(a[j]a[j1] ){ swap(a[j1],a[j]); front 1; } } if(front 0) break; } for(ll i 1;i n;i) cout a[i] ; }4堆排序1算法思想用堆实现优化选择排序2步骤1建堆升序大根堆降序小根堆流程从倒数第一个非叶子结点开始执行向下调整算法直至根节点2排序流程每次将堆顶元素与堆中最后一个元素交换堆大小减1然后将堆顶元素向下调整直至堆中只有一个元素3代码#include iostream using namespace std; const int N 1e5 10; int n; int a[N]; // down函数向下调整parent父节点len当前堆的有效大小 void down(int parent, int len) { int child parent * 2; // 左孩子下标 while(child len) { // 如果右孩子存在且右孩子值更大child切换到右孩子 if(child 1 len a[child 1] a[child]) child; // 父节点已经大于等于最大孩子不用调整直接退出 if(a[parent] a[child]) return; swap(a[parent], a[child]); parent child; // 父节点下沉到孩子位置 child parent * 2; // 更新为新的左孩子 } } void heap_sort() { // 第一步建大根堆从最后一个非叶子结点 n/2 往前遍历到1 for(int i n / 2; i 1; i--) { down(i, n); } // 第二步堆排序不断把堆顶最大值放到数组末尾 for(int i n; i 1; i--) { swap(a[1], a[i]); // 堆顶(最大值)和堆末尾元素交换 down(1, i - 1); // 对剩下i‑1个元素重新向下调整 } } int main() { cin n; for(int i 1; i n; i) cin a[i]; heap_sort(); for(int i 1; i n; i) cout a[i] ; return 0; }5快速排序1算法图解2算法思想1待排序区间选一个基准元素按基准元素大小把区间分为两部分2递归处理两部分直到区间长度为13缺陷so......在实现过程中我们会遇到哪些问题呢1基准元素怎么选2元素大量重复递归层数过多---进化一下吧4优化优化一随机选择基准元素随机函数srand(time(0));//种下随机数种子 rand();//获得一个随机数 rand()%(right-left1)left//区间随机数优化二数组分三块​ #include iostream #include ctime using namespace std; const int N 1e5 10; int n; int a[N]; // 获取随机下标 int get_random(int left, int right) { return rand() % (right - left 1) left; } void quick_sort(int left, int right) { if(left right) return; int p get_random(left, right); int pivot a[p]; // 基准值 // 荷兰国旗三分 int l left - 1, i left, r right 1; while(i r) { if(a[i] pivot) swap(a[l], a[i]); else if(a[i] pivot) i; else swap(a[--r], a[i]); } quick_sort(left, l); quick_sort(r, right); } int main() { srand(time(0)); cin n; for(int i 1; i n; i) cin a[i]; quick_sort(1, n); for(int i 1; i n; i) cout a[i] ; return 0; } ​6.并归排序1算法思想分治1只要能分就一分为二将左右区间排序2左右区间合并一起2代码#include iostream using namespace std; const int N 1e5 10; int n; int a[N]; int tmp[N]; // 临时数组用来合并时暂存数据 void merge_sort(int left, int right) { if(left right) return; // 区间只有一个数不用排序 // 1.区间对半拆分 int mid (left right) 1; //等价于 (leftright)/2 // [left , mid] 和 [mid1 , right] merge_sort(left, mid); //递归排左半段 merge_sort(mid 1, right); //递归排右半段 // 2.合并两个已经有序的数组 int cur1 left, cur2 mid 1, i left; while(cur1 mid cur2 right) { if(a[cur1] a[cur2]) tmp[i] a[cur1]; else tmp[i] a[cur2]; } // 把剩下没处理完的部分直接拷贝进tmp while(cur1 mid) tmp[i] a[cur1]; while(cur2 right) tmp[i] a[cur2]; // 把tmp结果复制回原数组a for(int j left; j right; j) { a[j] tmp[j]; } } int main() { cin n; for(int i 1; i n; i) cin a[i]; merge_sort(1, n); for(int i 1; i n; i) cout a[i] ; return 0; }
返回列表