1.13 排序与查找&文件重定向
1.13 排序与查找&文件重定向
1. 文件重定向
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
//从文件 data.in中读入数据到输入流中,替代了我们手动输入数据的过程,所以read.in提前就需要建好,并存入数据
freopen("data.in", "r", stdin);
//将输出流的数据写入文件 data.out中,也就是控制台的输出数据被写入到文件中
freopen("data.out", "w", stdout);
int a,b; cin>>a>>b;
cout<<a+b;
return 0;
}
2. 排序
1. 冒泡排序
原理:走访未排序好的数列,一次比较两个相邻元素,如果它们的顺序错误就把它们交换过来。
走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
冒泡排序算法的运作如下:
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int N=1e3;
int a[N];
int main(){
freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
int n; cin>>n;
for(int i=1; i<=n; i++) cin>>a[i];
//冒泡排序:每次比较两个相邻元素,直到所有元素都比较完成
for(int i=1; i<=n; i++){
for(int j=1; j<=n-i; j++){
if(a[j]>a[j+1]){//升序排列
int t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}//每次冒泡结束都输出一次当前的结果
for(int i=1; i<=n; i++) cout<<a[i]<<" "; cout<<endl;
}
return 0;
}
2. 选择排序
原理:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
和冒泡排序的区别就在于不是每次比较两个相邻元素,但是其原理和实现大同小异。
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int N=1e3;
int a[N];
int main(){
freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
int n; cin>>n;
for(int i=1; i<=n; i++) cin>>a[i];
//选择排序:每次选择最大(或最小)放在最前面
for(int i=1; i<=n; i++){
int min=i;//假设当前就是最小值
for(int j=i; j<=n; j++){
if(a[min]>a[j]) min=j;//升序排序,记录最小值的下标
}
if(min!=i){//如果最小值的下标发生变化,则交换当前值与最小值
int temp = a[min];
a[min] = a[i];
a[i] = temp;
}
}
for(int i=1; i<=n; i++) cout<<a[i]<<" "; cout<<endl;
return 0;
}
3.插入排序
每步将一个待排序的记录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。
#include<iostream>
using namespace std;
const int N=1e5+10;
int n,a[N];
int main() {
cin>>n;
for(int i=1; i<=n; i++) cin>>a[i];
// 插入排序:将元素插入一个有序序列中
for(int i=2; i<=n; i++){
// [1, i-1]
int k=i; // 当前要插入的元素
for(int j=i-1; j>=1; j--){
if(a[k] < a[j]) swap(a[k], a[j]), k=j;
else break;
}
}
for(int i=1; i<=n; i++) cout<<a[i]<<" "; cout<<endl;
return 0;
}
4. 桶排序
桶排序其实可以看作是一个计数问题
比如:有一串数据:4 5 4 6 3 1 1 2
可以发现,数据中最小值为1,最大值为6,
那么我们可以采用对数字进行计数的方式来记录。
a[i] = n; //表示数据 i 出现的次数为 n次
那么对数据:4 5 4 6 3 1 1 2
a[1] = 2
a[2] = 1
a[3] = 1
a[4] = 2
a[5] = 1
a[6] = 1
再按照下标从小到大输出下标,每一个下标 i 的输出次数与 a[i]的值相等。
则上述数据输出的结果为:1 1 2 3 4 4 5 6
然后就发现了一个神奇的现象,数据竟然就排好序了,而且是升序排序。
如果要降序序排序,那么输出下标按从大到小,降序排序即可。
程序实现:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e3;
int a[N];
int main(){
freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
int n,max=0,min=1e4; cin>>n;
for(int i=1; i<=n; i++) {
int x; cin>>x;
a[x]++; //桶排序关键,计数
if(max<x) max=x;//最大值
if(min>x) min=x;//最小值
}
for(int i=min; i<=max; i++){//用来规范数据范围
for(int j=1; j<=a[i]; j++){
cout<<i<<" ";
}
}
return 0;
}
5. sort
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e4;
int a[N];
int main(){
freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
int n; cin>>n;
for(int i=0; i<n; i++) cin>>a[i];
sort(a, a+n);//a[0]~a[n-1]
//sort(首地址, 首地址+元素个数)
// 如果输入从1开始,那么首地址需要变化,如下
// sort(a+1, a+1+n);// a[1]~a[n]
return 0;
}
除了上述排序方法外还有:快速排序,归并排序,希尔排序,堆排序....
3. 查找
1. 顺序查找
其实所谓的顺序查找就是将所有可能的答案进行一次遍历,直到找到正确的答案才结束。
#include<iostream>
using namespace std;
int main(){
int a[10]={1,2,3,4,5,6,7,8,9,0};
//顺序查找:一个一个的查找
int x=4;
for(int i=0; i<10; i++){
if(a[i]==x) {
cout<<i<<" "<<a[i];
break;//找到答案退出
}
}
return 0;
}
2. 二分查找
二分查找是基于一段有序序列的查找算法,每一次查找是从序列的中间开始查找,所以叫二分查找。
#include<iostream>
using namespace std;
int main(){
int a[10]={0,1,2,3,4,5,6,7,8,9};
//二分查找:从中间开始查找
int l=0, r=9, x=4;
while(l<=r){
int mid = (l+r)/2;
if(a[mid]==x) {
cout<<mid<<" "<<a[mid];
break;//找到答案退出
}else if(a[mid]<x){
l = mid+1;//答案一定在右边
}else if(a[mid]>x){
r = mid-1;//答案一定在左边
}
}
return 0;
}