《算法笔记》轮子

这是一篇关于算法和数据结构的笔记总结,包括进制转换、全排列、区间贪心、二分查找、快速幂等经典算法,以及STL的使用,如set、queue、priority_queue、stack等容器的特性。还涵盖了数据结构中的栈、链表、树等,并探讨了DFS、BFS遍历策略及其在实际问题中的应用。
摘要由CSDN通过智能技术生成

血泪教训与总结!

检查时先检查是否将=写为==!

函数有返回值时,退出函数用return NULL; void时可直接用return;

进制转换

p进制的x转为十进制y:
int y=0; product=1;
while(x!=0){
	y += (x%10)*product;   //获取x个位后乘以次方
	x /= 10;  						//x去掉个位
	product*=p;
}

十进制y转换为p进制
int d[40],num=0;
do{
	d[num++] = y % p;
	y/=p;
}while(y!=0);					//之所以用do...while是因为避免y=0时d数组为空。d数组倒序输出

##字符串hash

//大写字母
int hashFunc(char S[], int len){
	int id=0;
	for(int i=0; i<len; i++){
		id=id*26+(S[i]-'A);
	}
	return id;
}
              
//大写字母 52进制转十进制
int hashFunc(char S[], int len){
	int id=0;
	for(int i=0; i<len; i++){
		if(S[i]>='A'&&S[i]<='Z'){
      id=id*52+(S[i]-'A);
    }else if(S[i]>='a'&&S[i]<='z'){
      id=id*52+(S[i]-'a')+26;
    }
	}
	return id;
}

全排列

#include<bits/stdc++.h>
using namespace std;
const int maxn=11;
int n,P[maxn],hashTable[maxn]={false};

void generateP(int index){
	if(index == n+1){					//循环边界,到达位数输出
		for(int i=1; i<=n; i++){
			cout<<P[i];
		}
		cout<<endl;
		return; 
	}
	
	for(int x=1; x<=n; x++){		//每一次循环代表以x为第一个数字的排列
		if(hashTable[x]==false){
			P[index]=x;
			hashTable[x]=true;
			generateP(index+1);
			hashTable[x]=false;
		}
	}
} 

int main() {
	n=3;
	generateP(1);
	return 0;
}

区间贪心


const int maxn=110;

struct Inteval{
	int x,y;
}I[maxn];

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

二分查找

mid = (left + right) / 2;				  //可能会超出int范围
mid = left + (right - left) / 2;	//这样处理避免溢出		

快速幂

给定a,b,m,求 a b a^b ab % m

如果b是奇数,则 a b = a ∗ a b − 1 a^b=a*a^{b-1} ab=aab1

如果b是偶数,则 a b = a b / 2 ∗ a b / 2 a^b=a^{b/2}*a^{b/2} ab=ab/2ab/2

typedef long long LL;
LL binaryPow(LL a, LL b, LL m){
	if(b == 0) return 1;
	if(b % 2 == 1) return a * binaryPow(a, b-1, m) % m; 	//也可为b&1,奇数末位为1
	else {
		LL mul= binaryPow(a, b/2, m);
		return mul * mul % m; //不能写成binaryPow(a, b/2, m) * binaryPow(a, b/2, m) % m
	}
}

two pointers

while(i < j){
	if(a[i] + a[j] == m){
		printf();
		i++;
		j--;
	}else if(a[i] + a[j] < m){
		i++;
	}else{
		j--;
	}
}

生成随机数

srand((unsigned)time(NULL));
//[a,b]之间
rand()%(b-a+1)+a;
//超出RAND_MAX
(int)((double)rand()/RAND_MAX*(b-a+1)+a);

整数转换为数组

void to_array(int n, int num[]){
	for(int i = 0; i < 4; i++){
		num[i] = n % 10;
		n /=10;
	}
}

int to_number(int num[]){
	int sum = 0;
	for(int i = 0; i < 4; i++){
		sum = sum*10+num[i];
	}
	return sum;
}

最大公约数、最小公倍数

int gcd(int a, int b){
	if(b==0) return a;
	else return gcd(b, a%b);
}

//法二
int gcd(int a, int b){
	return !b ? a : gcd(b, a%b);
}

//最小公倍数
d为最大公约数,因ab/d可能会造成溢出,故用
a/bd 表示最小公倍数

分数四则运算

struct Fraction{
       int up,down;
};

Fraction reduction(Fraction result){
       if(result.down<0){   //分母为负数
              result.up = - result;
              result.down = - result.down;
       }
       if(result.up==0){    //分子为0
              result.down=1;
       }else{
              int d = gcd(abs(result.up), abs(result.down));
              result.up /= d;
              result.down /= d;
       }
       return result;
}

//加法示例
Fraction f1,f2,result;
result.up=f1.up+f2.up;
result.down=f1.down+f2.down;
result=reduction(result);

判断素数

const int maxn=101;     //素数表长
int prime[maxn],pNum=0; //prime存放素数,pNum为素数个数
bool p[maxn]={0};       //i为素数,则p[i]为false


bool isPrime(int n){
       if(n<=1) return false;
       int sqr=sqrt(n);
       for(int i=2; i<=sqr; i++){
              if(n%i==0) return false;
       }
       return true;
}

//筛法 素数打表
void Find_Prime(){
    for(int i=2; i<maxn;i++){
        if(!p[i]){
            prime[pNum++]=i;
            for(int j=i+i;j<maxn;j+=i){
                //筛去所有i的倍数
                p[j]=true;
            }
        }
    }
}

内存开辟与回收

C:

node* p = (node*)malloc(sizeof(node))

free§

C++:

node* p = new node;

delete§

STL

set

set中元素唯一,若要处理不唯一,则用multiset,c++11增加了unordered_set,以散列表代替红黑树,用于只去重不排序的情况

string

//printf输出string

string str="abc";

printf("%s",str.c_str());


str.insert(pos,string);
str.insert(it,it2,it3);将[it2,it3)插入it处

str.erase(first,last);//删除[first,last),first,last为迭代器
str.erase(pos,length);

str.substr(pos,len)
                         
//string::npos是一个值为-1的常数,但其类型为unsigned_int,因此可认为是unsigned_int类型的最大值,用以作为find函数失配时的返回值
str.find(str2)//找到则返回str2第一次出现的位置,否则返回string::npos
str.find(str2,pos)//从pos位置开始find
                         
str.replace(pos,len,str2)

queue

只能通过front()和back()来访问队首队尾元素,

push()添加到队尾

pop()删除队首元素

empty()检测是否为空队列

size()获得队内元素个数

priority_queue

:使用堆实现的默认将当前队列的最大(优先级最高)元素置于队首的容器

只能通过top()访问队首(堆顶)元素,没有front()和back()

stack

只能通过top()访问栈顶元素,没有front()和back()

pair

当想要将两个元素捆绑在一起而又不想定义一个结构体时,用它!

临时构建 pair:

  • pair<string,int>(“haha”,5)
  • make_pair(“haha”,5);

比较大小:可直接使用比较运算符,先比较first,first相等比较second

abs() fabs() swap() reverse() fil()

abs():整数

fabs():浮点数

swap() 交换

reverse() 反转,[it,it2),也可对string字符串进行反转

fill() 给数组或容器的某一区间赋任意值

next_permutation():给出一个序列在全排列中的下一个序列

int a[10]={1,2,3};
do{
	cout<<a[0]<<a[1]<<a[2];
}while(next_permutation(a,a+3));
//next_permutation()在已经到达全排列的最后一个时会返回false

字符串大小排序

bool cmp(string str1,string str2){
	return str1.length() > str2.length();
}

lower_bound() 和 upper_bound()

lower_bound(first,last,val) : [first,last)范围内第一个大于等于val的元素的位置

upper_bound(first,last,val) : [first,last)范围内第一个大于val的元素的位置

如果没有需要寻找的元素,则返回可以插入该元素的位置的指针或迭代器

数据结构

STL中没有实现stack的清空,需要使用while循环反复pop(),事实上 ,直接重新定义一个栈就行

中缀转后缀

#include<bits/stdc++.h>
using namespace std;

struct node{
    double num;
    char op;
    bool flag; //true表示操作数
};

string str;
stack<node> s;  //操作符栈
queue<node> q;  //后缀表达式序列
map<char,int> op;   //得到相应字符的优先级数字,用于直接比较

void Change(){  //中缀转后缀
    double num;
    node temp;
    for(int i=0; i<str.length();){
        //操作数
        if(str[i]>='0'&& str[i]<='9'){
            temp.flag=true;
            temp.num=str[i++]-'0';
            //若数字不止一位
            while(i<str.length() && str[i]>='0'&& str[i]<='9'){
                temp.num=temp.num*10+(str[i]-'0');
                i++;
            }
            q.push(temp);
        }else{
        //操作符
            temp.flag=false;
            while(!s.empty() && op[str[i]] <= op[s.top().op]){
                q.push(s.top());
                s.pop();
            }
            temp.op=str[i];
            s.push(temp);
            i++;
        }
    }

    while (!s.empty()){
        q.push(s.top());
        s.pop();
    }
}

double Cal(){
    double temp1,temp2; 
    node cur,temp;
    while(!q.empty()){
        cur=q.front();
        q.pop();
        if(cur.flag) s.push(cur);
        else{
            //如果是操作符
            temp2=s.top().num;
            s.pop();
            temp1=s.top().num;
            s.pop();
            temp.flag=true;//临时记录操作数
            if(cur.op == '+') temp.num=temp1+temp2;
            else if(cur.op == '-') temp.num=temp1-temp2;
            else if(cur.op == '*') temp.num=temp1*temp2;
            else temp.num=temp1/temp2;
            s.push(temp);
        }
    }
    return s.top().num;
}

int main(){
    op['+']=op['-']=1;
    op['*']=op['/']=2;
    while(getline(cin,str),str!="0"){
        for(string::iterator it=str.end(); it!=str.begin();it--){
            if(*it ==' ') str.erase(it);
        }
        while(!s.empty()) s.pop();
        Change();
        cout<<Cal();
    }
    return 0;
}

链表

  • 动态链表
  • 静态链表:hash原理
struct Node{
	typename data;
	int next;
}node[size];

DFS

DFS会遍历所有路径

根据题目的限制来节省DFS计算量的方法称为**剪枝**

//背包
void DFS(int index,int sumW,int sumC){
    if(index==n){
        if(sumW<=V && sumC>=maxValue)
            maxValue=sumC;
        return;
    }
    //对每个物品,有选和不选两种情况,都要遍历,故需两次DFS
    DFS(index+1,sumW,sumC);
    DFS(index+1,sumW+w[index],sumC+c[index]);
}

BFS

void BFS(int s){
    queue<int> q;
    q.push(s);
    while(!q.empty()){
        取top元素;
        使用top元素;
        pop出队;
        将top的下一层结点中未曾入队的结点全部入队,并设置为已入队;
    }
}

https://blog.csdn.net/y_dd6011/article/details/89715169

STL中的queue的push操作只是产生了该元素的一个副本入队,该元素与其副本无关联,修改这个不会影响另一个,因此,当需要修改队列中的元素而不仅仅是访问时,队列中最好放元素的编号而不是其本身(例如数组下标)

祖先结点,子孙结点

完全二叉树的存储结构

  • 判断结点为叶子结点 : 该结点的左子结点的编号root * 2大于结点总数n
  • 判断结点为空结点 : 该结点的编号root大于结点总数n

先序,中序,后序遍历一般使用DFS,层序使用BFS

无论是知道先序序列还是后序序列还是层序序列,只有知道中序遍历序列才能唯一的确定一棵树

一般树的先根遍历序列与DFS序列相同,层序遍历序列与BFS序列相同

BST(二叉查找树)

数据域有序,左子树<根<右子树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值