算法入门之排序(《算法笔记》)

冒泡排序

【冒泡排序】每趟依次两两对比元素,并且每趟会确定最大/小元素的最终位置。

#include <iostream>
#include <vector>
using namespace std;
void swap(int &a, int &b);
int main()
{
	int n;
	cin >> n;
	vector<int> v(n);   //大小为n的数组 
	for ( int i=0; i<n; i++ )
		cin >> v[i];
	
	//冒泡排序-->从小到大排列 
	for ( int i=0; i<n-1; i++ ){  //共比较n-1趟 
		for ( int j=1; j<n; j++ ){
			if ( v[j-1]>v[j] )
				swap(v[j-1],v[j]);
		}
	}
	
	cout << v[0];
	for ( int i=1; i<n; i++ )
		cout << " " << v[i];
	
	return 0;
}
void swap(int &a, int &b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

实现核心其实就是交换两个数。

选择排序

【简单选择排序】序列分为有序部分和待排序部分,每趟从待排序部分找出最小/大值增加到有序部分的末尾。

#include <iostream>
#include <vector>
using namespace std;
void swap(int &a, int &b);  //交换两个数 
int find_minindex(int k, int n, vector<int> a);  //找到数组a的最小值下标,k为待排序起始下标,n为数组长度 
int main()
{
	int n;
	cin >> n;
	vector<int> v(n);   //大小为n的数组 
	for ( int i=0; i<n; i++ )
		cin >> v[i];
	
	//简单选择排序-->从小到大排列
	for ( int i=0; i<n; i++ ){  //共交换n趟 
		int min = find_minindex(i,n,v);
		cout << v[min] << endl;
		swap(v[i],v[min]);
	}
	//0 2 4 1 2  -->  1 0 2 2 4
	cout << v[0];
	for ( int i=1; i<n; i++ )
		cout << " " << v[i];
	
	return 0;
}
void swap(int &a, int &b)
{
	int tmp = a;
	a = b;
	b = tmp;
}
int find_minindex(int k, int n, vector<int> a)
{
	int min = k;
	for ( int i=k+1; i<n; i++ ){  //共比较k-1趟 
		if ( a[i]<a[min] )
			min = i;
	} 
	return min;
}

实现核心比冒泡排序多了个找最小/大值下标,整合如下

void selectSort(int k, int n, vector<int> a)
{
	for ( int i=0; i<n; i++ ){  //进行n趟操作 
		int min = k;
		for ( int j=i+1; j<n; j++ ){  //选出[i,n-1]中的最小元素,下标为min 
			if ( a[i]<a[min] )
				min = i;
		}
		swap(a[i],a[min]);
	}
}

插入排序

【直接插入排序】序列仍分为有序和待排序两个部分,但这次是将待排序列中的元素依次插入到有序序列的合适位置中去。

void insertSort(int n, vector<int>a )
{
	for ( int i=1; i<n; i++ ){  //共n-1趟操作 
		int tmp = a[i], j = i;  
		//注意由于后面要移动数据,所以这里先把待插入元素存在tmp中,并且后面的比较与插入操作都要用tmp 
		while ( j>0 && a[j-1]>tmp ){  //从后向前比较 
			a[j] = a[j-1];  //把v[j-1]后移至v[j] 
			j--;
		}
		a[j] = tmp;  //最终插入的位置为j
	}
} 

使用sort函数排序

#include <algorithm>
using namespace std;
sort(begin,end_next,cmp);

【sort函数】参数分别为首元素地址(必填),尾元素地址的下一个地址(必填),比较函数(非必填)(默认递增排序)。

👉如何实现比较函数cmp

sort函数默认递增排序,即相当于

bool cmp(ElemType a, ElemType b){
	return a < b;
}

(1)基本数据类型数组的排序

bool cmp(ElemType a, ElemType b){
	return a > b;
}

可以理解为当a>b时把a放在b前面

(2)结构体数组的排序此

此时,cmp函数传入的参数类型改为结构体类型。
定义结构体如下:

struct node{
	int x, y;
}ssd[10];

可进行一级排序:如将数组ssd按照x从大到小排序

bool cmp(node a, node b){
	return a.x > b.x;
}

也可以进行二级排序:如将数组ssd先按照x从大到小排序,但当x相等的情况下,按照y的大小从小到大来排序

bool cmp(node a, node b){
	if(a.x != b.x)  return a.x > b.x;
	else return a.y < b.y;
}

(3)容器的排序

在STL标准容器中,只有vector、string、deque是可以使用sort的。(set、map容器中元素本身就有序,不允许使用sort排序)。
*注意:对vector中元素进行排序时,cmp参数类型与vector中元素类型一致即可,如vector元素类型为int时,cmp(int a, int b)即可。

【PAT A1025] PAT Ranking(25)

原题目:1025 PAT Ranking (25 分)
题目大意: 有N个考场(1-N),接着给出每个考场的考生数量K及每个考生的注册号和成绩。要求:①计算考生总数;②生成总的成绩排行榜,成绩相同时排名相同且按注册号非递减排序。
分析: ①定义结构体类型数组存放考生注册号、成绩、考场号、最终排名以及考场内排名。
②sort函数:先对每个考场的考生进行排名(在输入时完成),而后复制到总数组,再进行总的排名。
③cmp函数:分数不同时,按分数递减排序;分数相同时,按注册号递增排序。
④排名的计算:排序后,设置第一个元素的排名为‘1’,而后的元素,若与前一个元素成绩相同则排名也相同,否则排名为数组下标(从0开始时)+1(错误点)。
词汇: nondecreasing order非递减次序
其他词汇: simultaneously同时;ranklist排行榜;test location测试点;testee考生;registration number注册号

#include <iostream>
#include <vector>
#include <algorithm>
#include <string.h>
using namespace std;
struct testee{
    long long int no;  //注册号
    //char no[14];
    int score, finr, loc, locr;  //成绩,最终排名,考场号,考场内排名
};
bool cmp(testee a, testee b){
    if ( a.score!=b.score ) 
        return a.score>b.score;  //先按成绩递减排序
    else return a.no<b.no;  //再按注册号递增排序
    //else return strcmp(a.no, b.no)<0;
    /*//上述可写成:
    return a.score!=b.score ? a.score>b.score : a.no<b.no*/
}
int main()
{
    int n, k;
    cin >> n;
    vector<testee> fin;  //记录总情况
    for ( int i=1; i<=n; i++ ){  //n个考场
        cin >> k;
        vector<testee> v(k);  //记录每个考场的情况
        for ( int j=0; j<k; j++ ){
            v[j].loc = i;  //考场号为i
            cin >> v[j].no >> v[j].score;
            //scanf("%s %d", &v[j].no, &v[j].score);
        }
        sort(v.begin(), v.end(), cmp);  //考场内排序
        v[0].locr = 1;   //排序后设置第一个排名为‘1’
        fin.push_back(v[0]);  //将排名好的压入最终数组
        for ( int j=1; j<k; j++ ){  //计算考场内排名
            if ( v[j].score==v[j-1].score )
                v[j].locr = v[j-1].locr;
            else v[j].locr = j+1;
            /*//上述可写成:
        	v[j].score = (v[j].score==v[j-1].score) ? v[j-1].locr : j+1;*/
            fin.push_back(v[j]);  //将排名好的立即压入最终数组
        }
    }
    sort(fin.begin(), fin.end(), cmp);  //总排序
    fin[0].finr = 1;
    for ( int i=1; i<fin.size(); i++ ){   //总排名
        if ( fin[i].score==fin[i-1].score )
                fin[i].finr = fin[i-1].finr;
        else fin[i].finr = i+1;
        /*//上述可写成:
        fin[i].score = (fin[i].score==fin[i-1].score) ? fin[i-1].finr : i+1;*/
    }
    
    cout << fin.size() << endl;
    for ( int i=0; i<fin.size(); i++ )
        //printf("%s %d %d %d\n", fin[i].no, fin[i].finr, fin[i].loc, fin[i].locr);
        printf("%013ld %d %d %d\n", fin[i].no, fin[i].finr, fin[i].loc, fin[i].locr);
    
    return 0;
}

关于“复制结构体类型元素”

用vector容器时,可以将整个结构体类型元素压入push_back到另一个vector容器中,不需要对每个结构体的内容逐项“复制”。

关于“考生总数”的计算

使用vector的size()即可,不需另设变量cnt来统计。

关于“strcmp函数”

【strcmp函数】需要头文件string.h(不同于string);用来比较两个char型数组的字典序大小。需要注意的是,返回值不一定是+1或-1(与编译器有关),故判断用>0或<0为好。

错误点
1.分数不同时,第i个考生就是第i名,而不是上一排名+1。
2.关于学生注册号的存取:

关于长数字串的存储变量类型选取

(1)109以内都可以用int
(2)1016以内可以用long long
(3)但是在存储类似注册号这样的编号时,要防止编号以0开头,若用数字类型变量存储则会丢失编号开头的’0‘位。
👉解决办法:①仍用long long型,但输出的时候要用 %013ld
②用char型数组或者string类型:

关于char型数组和string类型

char型数组
·头文件:string.h(区别于头文件string)
·读入字符串时,%s识别空格作为字符串的结尾
·用strcmp比较大小
string类型

`头文件:string(还需要using namespace std;)
·一般用cin/cout,除非str.c_str()才可用printf
·可以直接比较大小

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值