模版以及数学知识总结 (c ++) (持续更新)

1.堆排序(建堆与堆的操作)

#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
using namespace std ;

void heapInsert(vector<int> &a, int index){						///建立大根堆,将数向上浮
    while(a[index] > a[(index - 1) / 2]){
        swap(a[index],a[(index - 1) / 2]) ;
        index = (index - 1) / 2 ;
    }
    return ;
}

void heapify(vector<int> &a, int index , int size){					///将数向下沉
    int left = index * 2 + 1 ;
    while ( left < size ){
//        int largest = left + 1 < size && a[left] > a[left+1] ? left : left+1 ;	///当 && 左右两边为真时才可以,且要对应,此种写法会导致错误
        int largest = left + 1 < size && a[left+1] > a[left] ? left + 1 : left ;
        largest = a[largest] > a[index] ? largest : index ;
        if ( largest == index ) break ;
        swap( a[largest] , a[index] ) ;
        index = largest ;
        left = index * 2 + 1 ;
    }
    return ;
}

void heap_sort(vector<int> &a){
    for ( int i = 0 ; i < a.size() ; i ++ ){
        heapInsert( a ,i ) ;
    }
    int size = a.size() ;
    swap(a[0],a[--size]) ;								///size每次减1,缩小范围
    while ( size > 0 ){
        heapify(a,0,size) ;
        swap(a[0],a[--size]) ;
    }
    return ;
}

(可用来解决逆序对问题)


2.快速排序与随机快排的简单实现

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std ;

pair<int,int>partition( vector<int> &a ,int l, int r ){///快排始终以最后一个值作为基准值来进行比对,递归到底
    int less = l-1,more = r ;
    while ( l < more ){
        if ( a[l] < a[r] ){
            swap(a[l++],a[++less]) ;			///   <=> l++ ;less++ ; 和自身交换;
        }
        else if ( a[l] > a[r] ){
            swap(a[l],a[--more]) ;
        }
        else{
            l ++ ;
        }
    }
    swap(a[more],a[r]) ;				///因为始终以最后一个数为基准,交换后彻底使中间部分等于基准值
    return make_pair(less+1,more);			///返回两个数用pari(相当于结构体) ,返回相等的区域的下标
}

void quickSort(vector<int> &a , int l , int r ){
    if ( l < r ){
        swap(a[l +rand()%(int)(r-l+1)],a[r]) ;		///加上这一句后变成随机快排,比不加快,在(l,r)范围内随机寻找一个数与a[r]交换,使随机值作为a[r],即基准值
        pair<int,int> p = partition(a,l,r) ;
        quickSort(a,l,p.first-1) ;			///p.first-1为小于刚刚的基准值的下标
        quickSort(a,p.second+1,r) ;			///p.second为大于刚刚的基准值的下标
    }							///中间就是等于基准值的部分
    return ;
}


3.归并排序(Merge Sort)

#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
using namespace std ;

void merge(vector<int> &a , int l , int mid , int r){
    int help[r-l+1] ;
    int p1 = l , p2 = mid + 1 ;
    int k = 0 ;
    while(p1 <= mid && p2 <= r){
        help[k++] = a[p1] < a[p2] ? a[p1++]:a[p2++] ;
    }
    while(p1 <= mid){
        help[k++] = a[p1++] ;
    }
    while(p2 <= r){
        help[k++] = a[p2++] ;
    }
    for ( int i = 0 ; i < r-l+1 ; i ++ ){
        a[l+i] = help[i] ;
    }
    return ;
}

void merge_sort(vector<int> &a, int l , int r){
    if( l == r ) return ;
    int mid = l + (( r - l ) >> 1) ;
    merge_sort(a,l,mid) ;
    merge_sort(a,mid+1,r) ;
    merge(a,l,mid,r) ;
    return ;
}


4.线段树(建树与查询区间最值操作)

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
const int MAXN = 1000005 ;
using namespace std ;

int segTree[MAXN] ;
int a[MAXN] ;

void build ( int node , int arr[] , int istart , int iend ){
    if ( istart == iend ) segTree[node] = arr[istart] ;
    else{
        int mid = (istart + iend) / 2 ;
        build( node * 2 + 1 , arr , istart , mid ) ;
        build( node * 2 + 2 , arr , mid + 1 , iend ) ;
        segTree[node] = max( segTree[node * 2 + 1] , segTree[node * 2 + 2] ) ;
    }
    return ;
}

int query( int node , int left_now , int right_now , int left_query , int right_query ){
    if ( left_query > right_now || right_now < left_now ) return 0 ;
    if ( left_now >= left_query && right_now <= right_query ) return segTree[node] ;
    int mid = ( right_now + left_now ) / 2 ;
    return max( query( node * 2 + 1 , left_now , mid , left_query , right_query ) ,
                query( node * 2 + 2 , mid + 1 , right_now , left_query , right_query)) ;
}
(线段树参考自 http://www.cnblogs.com/TenosDoIt/p/3453089.html )


5.分解质因数

1.

const int MAXN = 100005 ;  
int a[MAXN] ;        ///保存质因子的种类  
int b[MAXN] ;        ///保存某个质因子的系数,也就是某种质因子有多少个  

void Fac( int num , int &tot ){  
    tot = 0 ;  
    int now = num ;  
    for ( int i = 2 ; i <= sqrt(num) ; i ++ ){  
        if ( now % i == 0 ){  
            a[++tot] = i ;  
            b[tot] = 0 ;  
            while ( now % i == 0 ){  
                ++ b[tot] ;  
                now /= i ;  
            }  
        }  
    }  
    if ( now != 1 ){  
        a[++tot] = now ;  
        b[tot] = 1 ;  
    }  
    return ;  
}  

2.略微加速版

const int MAXN = 100005 ;  
int a[MAXN] ;        ///保存质因子的种类  
int b[MAXN] ;        ///保存某个质因子的系数,也就是某种质因子有多少个  
   
void Fac( int num , int &tot ){        //分解质因数模版  
    tot = 0 ;                          ///记录质因子个数  
    int now = num ;  
    if ( now % 2 == 0 ){               ///略微加速  
        a[++tot] = 2 ;  
        b[tot] = 0 ;  
        while ( now % 2 == 0 ){  
            ++ b[tot] ;  
            now /= 2 ;  
        }  
    }  
    for ( int i = 3 ; i <= sqrt(num) ; i += 2 ){        ///略微加速  
        if ( now % i == 0 ){  
            a[++tot] = i ;  
            b[tot] = 0 ;  
            while ( now % i == 0 ){  
                ++ b[tot] ;  
                now /= i ;  
            }  
        }  
    }  
    if ( now != 1 ){  
        a[++tot] = now ;  
        b[tot] = 1 ;  
    }  
//        for ( int i = 1 ; i <= tot ; i ++ ){  
//        cout << a[i] << " " << b[i] << endl ;  
//    }  
    return ;  
}  

6.极角排序

struct Point{                            ///设置点
    double x , y ;
}point[55] ;

double cross( Point a , Point b ){       ///设置叉积
    return a.x * b.y - a.y * b.x ;
}

bool cmp( Point a , Point b ){            ///设置比较函数
    if ( cross( a , b ) > 0 ) return 1 ;
    return 0 ;
}

题目POJ 2007

(参考自https://www.cnblogs.com/handsomecui/p/5022240.html)


7.树状数组

预备函数:

扫描二维码关注公众号,回复: 2332808 查看本文章

定义一个Lowbit函数,返回参数转为二进制后,最后一个1的位置所代表的数值.
例如,Lowbit(34)的返回值将是2;而Lowbit(12)返回4;Lowbit(8)返回8。
将34转为二进制,为0010 0010,这里的"最后一个1"指的是从2^0位往前数,见到的第一个1,也就是2^1位上的1.
程序上,((Not I)+1) And I 表明了最后一位1的值,
仍然以34为例,Not 0010 0010的结果是 1101 1101(221),加一后为 1101 1110(222), 把 0010 0010与1101 1110作AND,得0000 0010(2).
Lowbit的一个简便求法:

int lowbit(int x){
    return x&(-x);
}

lowbit函数原理详解请见:http://www.cnblogs.com/circlegg/p/7189676.html

新建:

定义一个数组 BIT,用以维护A的前缀和,则:

{\displaystyle BIT_{i}=\sum _{j=i-lowbit(i)+1}^{i}A_{j}}

具体能用以下方式实现:

void build(){ 
    for (int i = 1; i <= MAX_N; i++){
        BIT[i] = A[i - 1];
        for (int j = i - 2; j >= i - lowbit(i); j--)
            BIT[i] += A[j];
    }
}
//注:这里的求和将汇集到非终端结点(D00形式)
//BIT中仅非终端结点i值是 第0~i元素的和
//终端结点位置的元素和,将在求和函数中求得
//BIT中的index,比原数组中大1

修改:

假设现在要将A[i]的值增加delta,

那么,需要将BIT[i]覆盖的区间包含A[i]的值都加上delta.

这个过程可以写成递归,或者普通的循环.

需要计算的次数与数据规模N的二进制位数有关,即这部分的时间复杂度是O(LogN)

修改函数的C++写法

void edit(int i, int delta){
    for (int j = i; j <= MAX_N; j += lowbit(j))
        BIT[j] += delta;
}

求和:

假设我们需要计算\sum _{{i=1}}^{{k}}A_{i}的值.

  1. 首先,将ans初始化为0,将i初始化为k.
  2. 将ans的值加上BIT[i]
  3. 将i的值减去lowbit(i)
  4. 重复步骤2~3,直到i的值变为0

求和函数的C/C++写法

int sum (int k){
    int ans = 0;
    for (int i = k; i > 0; i -= lowbit(i))
        ans += BIT[i];
    return ans;
}

复杂度:

初始化复杂度最优为O(N)

单次询问复杂度O(\log N),其中N为数组大小

单次修改复杂度O(\log N),其中N为数组大小

空间复杂度O(N)

(树状数组参考自wiki)


猜你喜欢

转载自blog.csdn.net/colpac/article/details/79845042