算法笔记系列:4.1 排序 4.2 散列
4.1.1 选择排序
简单选择排序原理:每次都找出区间中最小的元素,并与区间第一个元素进行交换,不断缩小区间最终完成排序,时间复杂度O(n^2)
4.1.2 插入排序
直接插入排序原理:将后面的每一个元素依次插入前面的有序部分,最终整个序列有序
4.1.3 排序题与sort函数的应用
-
考试中一般使用C++中的sort函数进行编写
-
sort使用必须加上头文件 #include和 using namespace std
sort(首元素地址(必填),尾元素地址的下一个地址(必填),比较函数(选填));
- sort中的cmp比较函数:只要记住<号就是从小到大,>就是从大到小
【PAT A1025】PAT Ranking
思路:难点在于每个考场的排序怎么排,就是每一次输入一个考场学生的信息后,在这一考场的所有学生先进行排序,按排序输入考场排名
# include<cstdio>
# include<algorithm>
# include<cstring>
using namespace std;
struct Student
{
char register_num[15];
int final_rank;
int location_num;
int local_rank;
int score;
}stu[30010];
bool cmp(Student a,Student b){
if (a.score!=b.score) return a.score>b.score;
else return strcmp(a.register_num,b.register_num)<0;
}
int main(){
int N,K,total=0;
scanf("%d",&N);
for (int i=1;i<=N;i++){
scanf("%d",&K);
for (int n=0;n<=K-1;n++){
stu[n+total].location_num=i;
scanf("%s %d",&stu[n+total].register_num,&stu[n+total].score);
}
sort(stu+total,stu+total+K,cmp);
stu[total].local_rank=1;
for (int m=1;m<=K-1;m++){
if (stu[m+total].score==stu[m+total-1].score) stu[m+total].local_rank=stu[m+total-1].local_rank;
else stu[m+total].local_rank=m+1;
}
total+=K;
}
sort(stu,stu+total,cmp);
stu[0].final_rank=1;
for (int i=1;i<=total-1;i++){
if (stu[i].score==stu[i-1].score) stu[i].final_rank=stu[i-1].final_rank;
else stu[i].final_rank=i+1;
}
printf("%d\n",total);
for (int n=1;n<=total;n++){
printf("%s %d %d %d\n",stu[n-1].register_num,stu[n-1].final_rank,stu[n-1].location_num,stu[n-1].local_rank);
}
return 0;
}
4.2.1 散列的定义与整数散列
思想:直接把输入的数作为数组的下标来对这个数的性质进行统计
散列(hash) 将元素通过一个函数转换为整数,使得该整数可以尽量唯一的代表这个元素
当这个元素key本身就是整数时,常用的散列函数有直接地址法,除留余数法
除留余数法:注意表长Tsize必须不小于mod
H
(
k
e
y
)
=
k
e
y
%
m
o
d
H(key)=key\%mod
H(key)=key%mod
因此会出现不同的key值,H(key)一样的情况,为了解决这种冲突,常用的三种方法
-
线性探查法: 发现占用,就H(key)+1寻找,到表位就转到表头,不断挨个找直到找到
-
平方探查法:针对上面方法容易扎堆的错开寻找办法,寻找顺序为 H ( k e y ) + 1 2 、 H ( k e y ) − 1 2 、 H ( k e y ) + 2 2 、 H ( k e y ) − 2 2 H(key)+1^2、H(key)-1^2、H(key)+2^2、H(key)-2^2 H(key)+12、H(key)−12、H(key)+22、H(key)−22
-
链地址法:不计算新的hash值,而是把所有H(key)相同的key连接成一条单链表
一般来说用标准库中的map函数来直接使用hash功能,C++11以后可以用unordered_map更快
4.2.2 字符串hash初步
当key不是整数时,设计散列函数,这里举例当key是字符串时,映射为26进制(都是大写字符),52进制(大小写都有)
例题:给出N个字符串(恰好三位大写字符串),再给出M个查询字符串,问每个查询字符串在N个字符串中出现的次数
# include<cstdio>
int hashTable[26*26*26+10]={0};
char s[10000][5],temp[5];
int hashfunc(char s[],int len){
int key=0;
for (int i=0;i<len;i++){
key=key*26+(s[i]-'A');
}
return key;
}
int main(){
int N,M;
scanf("%d%d",&N,&M);
for (int i=0;i<N;i++){
scanf("%s",s[i]);
int id=hashfunc(s[i],3);
hashTable[id]++;
}
for (int i=0;i<M;i++){
scanf("%s",temp);
int id=hashfunc(temp,3);
printf("%d\n",hashTable[i]);
}
}