算法笔记(常用数据结构)

1.时间处理

PAT中有些问题把时间转换为以 s 为单位可以简化很多操作。

scanf("%d:%d:%d", &hh, &mm, &ss); //输入格式
int timeToInt(int hh, int mm, int ss){
    return hh * 3600 + mm * 60 + ss;
}
printf("%02d:%02d:%02d
", sumTime/3600, sumTime%3600/60, sumTime%60);  //输出转换为输入形式

2.日期处理

int month[13][2] = {//平年和闰年的每个月的天数
  {0, 0}, {31, 31}, {28, 29}, {31, 31}, {30,30}, {31, 31}, {30,30}, {31, 31}, {31, 31}, {30,30}, 
  {31, 31}, {30,30}, {31, 31}
}
bool isLeap(int year){ //判断是否是闰年
  return (year%4==0 && year%100!=0) || (year%400 == 0);
}

3.进制转换

//将P进制数x转换为十进制数y
int y = 0, product = 1;  //product在循环中会不断乘P,得到 1、P、P^2、P^3....
while (x != 0){
  y = y + (x%10) * product;  // x%10 是为了每次获取x的个位数
  x = x / 10;     // 去掉x的个位
  product = product * P;   
}

//将十进制数y转换为Q进制数z,采用  (除基取余倒排法)
int z[40], num = 0;   //数组z存放Q进制数y的每一位,num为位数
do{
  z[num++] = y % Q;  //除基取余
  y = y / Q;
} while(y != 0);   //当商不为0时进行循环

4.最大公约数、最小公倍数

int gcd(int a, int b){  //最大公约数
    if(b == 0) return a;
    if(a < b) return gcd(b, a);
    else return gcd(b, a%b);
}
int lcm = (int a, int b){  //最小公倍数
    return a*b/gcd(a, b);  //a,b的最小公倍数为a*b/最大公约数
    //考虑a*b可能溢出,可写为 a/d*b
}

5.分数的输入形式

struct Fraction{
    long long up, down;  //分子、分母
} result;
scanf("%lld/%lld", &result.up, &result.down);
//分数化简
Fraction reduction(Fraction result){
    if(result.down < 0){ //分母为负数,令分子分母都变为相反数
        result.up = -result.up;
        result.down = -result.down;
    }
    if(result.up == 0){ //如果分子为0,则令分母为1
        result.down = 1;
    }else{//如果分子不为0,则进行约分
        int d = gcd(abs(result.up), abs(result.down));  //分子分母的最大公约数
        result.up /= d;
        result.down /= d;
    }
}
//分数的加减乘除

6.判断是否为素数(Prime)

N不会被除自己以外的大于根号N的整数整除(减少运算复杂度)

bool isPrime(int n){ //判断n是否为素数
    if(n <= 1) return false;  //1即不为素数,也不为合数
    int sqr = (int)sqrt(1.0*n);
    for(int i=2; i<=sqr; i++){
        if(n%i == 0) return false;
    }
    return true;
}

7.C++ sort()排序函数

#include <algorithm>
sort( 首元素地址(必填), 尾元素地址的下一个地址(必填), cmp 比较函数(非必填) );
//比较函数不填则默认对前面给出的区间进行递增排序
//提供 cmp 函数实现排序规则
bool cmp(Student a, Student b){
  int s = strcmp(a.name, b.name);
    if(s != 0) return s < 0;  //按姓名字典序从小到大排序
    else return a.id < b.id;
}

8.字符串Hash

符串hash是指将一个字符串映射成为一个整数,使得该整数可以尽可能唯一地代表字符串S。

//A student name consist of 3 capital(大写) English letters plus a one-digit number
const int M = 26*26*26*10+1;
vector<int> vec[M];
int getID(char name[]){
    int id = 0;
    for(int i=0; i<3; i++){
        id = id * 26 + (name[i] - 'A');
    }
    id = id * 10 + (name[3] - '0');
    return id;
}

9.插入排序

void insertDort(int arr[], int n){//升序
    for(int i=1; i<n; i++){
        int temp = arr[i], j=i;
        while(j >0 && arr[i-1] > temp){
            arr[j] = arr[j-1];
            j--;
        }
        arr[j] = temp;
    }
}
//简便方法,使用sort函数
void insertDort(int arr[], int n){//升序
    for(int i=1; i<n; i++){
        sort(arr, arr+i+1); //*****
    }
}

10.归并排序

void mergeSort(int arr[], int n){
    for(int step = 2; step/2 <=n; step *= 2){
        for(int i=0; i<n; i+=step){
            sort(arr+i, arr+min(i+step, n));  //使用sort函数的技巧
        }
    }
}

11.二分查找

//前提是数组有序
int binarySearch(int arr[], int left, int right, int x){
    int mid;
    while(left <= right){
        mid = (left + right) / 2;
        if(arr[mid] = x)  return mid;  //找到解,返回mid
        else if(arr[mid] < x) left = mid + 1;
        else right = mid -1;
    }
    return -1;  //解不存在
}
//在a[i+1]~a[n-1]中查找第一个超过a[i]*p的数,返回其位置给j
int j = upper_bound(arr+i+1, arr+n, (long long)arr[i]*p) - arr;
//在a[i+1]~a[n-1]中查找第一个大于或等于a[i]*p的数,返回其位置给j
int j = upper_bound(arr+i+1, arr+n, (long long)arr[i]*p) - arr;

12.数组中两个数据交换使用 swap()函数

swap(arr[1], arr[2]);

13.常用定义静态链表的格式

struct Node{
    int address; //结点地址
    int data;  //数据域
    int next; //指针域
    int order; //结点在链表上的序号
    XXX;  //
} node[100]; //结点的某个性质,不同的题目会有不同的设置

14.质因子分解

//对一个整数n来说,如果它存在[2,n]范围内的质因子,要么这些质因子全部小于等于 sqrt(n),要么只存在一个大于sqrt(n)的质因子,而其余质因子全部小于等于sqrt(n)
struct factor{
    int x, cnt;  //x为质因子,cnt为其个数
}fac[10];
if(n%prime[i]==0){ //prime为质数表,如果prime[i]是n的因子
    fac[num].x = prime[i]; //记录该因子
    fac[num].cnt = 0;
    while(n%prime[i] == 0){  //计算出质因子prime[i]的个数
        fac[num].cnt++;
        n /= prime[i];
    }
    num++;  //不同质因子个数加 1
}
if(n!=1){  //如果无法被根号n以内的质因子除尽
    fac[num].x = n;  //那么一定有一个大于根号n的质因子
    fac[num++].cnt = 1;
}

15.计算n!中有多少个质因子p

int cal(int n, int p){
    int ans = 0;
    while(n){
        ans += n/p;  //累加n/p^k
        n /= p;    //相当于分母多乘一个p
    }
    return ans;
}
原文地址:https://www.cnblogs.com/dear_diary/p/8616248.html