算法中琐碎知识点(排序、哈希散列、进制转化、C++)

一、进制转化

  • 对于一个P进制想要转化为Q进制的数,需要分成两步:
1. 将P进制数x转化为十进制数y;
int y = 0, product = 1;//product在循环中会不断乘P,得到1, p,p^1.....
while(x != 0){
    y += (x % 10) * product;
    x /= 10;
    product *= P;
}
2. 将十进制数y转化为Q进制z;
  • 采用除基取余法,所谓基是指进制Q,每次将数除以Q,然后将得到的余数作为低位存储,而商继续除以Q,最后当商为0时,将所有位从高到低输出就可以得到z;
int z[40], num = 0;
do{
    z[num++] = y % Q;
    y /= Q;
}while(y != 0);
  • 这样将z数组从高位z[num-1]到低位z[0]即为Q进制z,进制转换完成。

二、各种排序

  • 需要一个判断每一次排序后是否一致的函数:
bool isSame(int A[], int B[]){
    for(int i = 0; i < n; i++){
        if(A[i] != B[i]) return false;
    }
    return true;
}
  • 需要一个进行下一轮后输出结果的函数
void showArray(int A[]){
    for(int i = 0; i < n; i++){
        if(i != 0) printf(" ");
        printf("%d", A[i]);
    }
    printf("\n");
}
  • 需要一个每一步排序判断的函数,即与具体的算法进行结合;
bool insertSort(){
    bool flag = false;
    for(int i = 1; i < n; i++){
        if(i != 1 && isSame(tempOri, change)){
            flag = true;
        }
        int temp = tempOri[i], j = i;
        while(j > 0 && temp < tempOri[j-1]){
            temp[j] = temp[j-1];
            j--;
        }
        if(flag == true){
            return true;
        }
    }
    return false;
}
1. 选择排序
  • 对于一个序列A[N],进行N趟排序,第i次将i~N中选出最小的元素,然后将其与A[i]位置的元素进行交换;
void seleteSort(){
    for(int i = 0; i < n; i++){
        int k = i;
        for(int j = i; i < n; i++){
            if(A[j] < A[k]){
                k = j;
            }
        }
        int temp = A[i];
        A[i] = A[k];
        A[k] = temp;
    }
}
2. 插入排序
  • 默认将A[N]序列的前方1~i-1位为有序,然后将第i位插入到其中,具体实现方法为,临时使用一个变量,然后存储A[i],变量j = i,然后从i-1个元素开始比较,如果大于它,将第i-1位覆盖掉A[i], 说明第i为可以往前插入,然后j--;
int A[Maxn], n;//数组元素个数为n,下标从1~n
void insertSort(){
    for(int i = 2; i <= n; i++){
        int temp = A[i], j = i;
        while(j > 1 && temp < A[j - 1]){
            A[j] = A[j - 1];
            j--;
        }
        A[j] = temp;
    }
}
3. 2路-归并排序
  • 原理是通过每次将两组有序序列再进行排序,最后进行递归处理即可,首先将左边的进行递归排序,然后是右边,最后进行合并即可
void merge(int A[], int L1, int R1, int L2, int R2){
    int i = L1, j = L2;
    int temp[maxn], index = 0;
    while(i <= R1 && j <= R2){
        if(A[i] < A[j]) temp[index++] = A[i++];
        else temp[index++] = A[j++];
    }
    while(i <= R1) temp[index++] = A[i++];
    while(j <= R2) temp[index++] = A[j++];
    for(int i = 0; i < index; i++){
        A[L1 + i] = temp[i];
    }
}
void mergeSort(int A[], int left, int right){
    if(left < right){
        int mid = (left + right) / 2;
        mergeSort(A, left, mid);
        mergeSort(A, mid + 1, right);
        merge(A, left, mid, mid + 1, right);
    }
}
4. 快速排序
  • 每次将主元Left上的元素放到它的基位上,也就是左边元素都小于它,右边元素都大于它, 关键是它的Partition函数,使用temp接收数组左边第一个元素,然后分别使用指针指向数组的第一个元素和最后一个元素,结束标志是左边指针和右边指针重合时,首先对右边进行查找到第一个小于temp的, 然后将该值赋到左边第一个值处,左边同理,最后将temp值放入left终止处,返回left位置;
  • 最终函数关键是第一次返回的主元位置,将数组划分为两个部分,然后递归继续划分
int Partition(int A[], int left, int right){
    int temp = A[left];
    while(left < right){
        while(left < right && A[right] > temp) right--;
        A[left] = A[right];
        while(left < right && A[left] < temp) left++;
        A[right] = A[left];
    }
    A[left] = temp;
    return left;
}
//关键是第一次返回的主元位置,将数组划分为两个部分,然后递归继续划分
void qiuckSort(int A[], int left, int right){
    if(left < right){
        int pos = Partition(A, left, right);
        quickSort(A, left, pos - 1);
        quickSort(A, pos + 1, right);
    }
}

三、哈希散列(key是整数)

1. 插入
  • 直接将输入的数作为数组下标来对这个数的性质进行统计,用空间换时间,一般这样处理每个数不会超过10的5次方
  • 散列就将一个元素是通过一个函数转化为一个整数,使得该整数尽量唯一的代表这个元素。
  • 使用一个v数组进行存储转换后的下标,hash数组用于记录是否插入到散列中;
	vector<int> v(n), hash(m);
	for(int i = 0; i < n; i++){
		scanf("%d", &v[i]);
		int size = 0;
		while(size < m){
			if(hash[(v[i] + size*size) % m] != 0){
				size++;
			}else{
				hash[(v[i] + size*size) % m] = 1;
				v[i] = (v[i] + size*size) % m;
				break;
			}
		}
		if(size >= m) v[i] = -1;
	}
2. 查找
  • 查找的时候,可以根据上面插入时候的hash表,每次进行查找,方法基本一致,统计查找次数,有一点区别是,这个时候size的界限是小于等于m,而不是小于m
  • 同时,如果查到到hash值为空,也应该停止查找;
3. 常用的散列函数:
  • 直接定址法
  • 平方取中法
  • 除留余数法(常用)
  • 公式:H(key) = key % mod, 一般将mod取成Tsize, mod一般是个素数。
bool isPrime(int n){
    if(n <= 1) return false;
    int sqr = (int)sqrt(n);
    for(int i = 2; i <= sqr; i++){
        if(n % i == 0) return false;
    }
    return true;
}
4. 除留余数法常用解决冲突的方法
  • 线性探测法,如果被占用,那么就加一。
  • 平方探测法,当位置被占有时,将k等于1^2, 2^2, 3^2,进行查找,如果k在[0, Tsize)都找不到位置,那么当k>=Tsize也找不到位置;
  • 链地址法,直接将余数相同的值,放入一个链表中;
posted @ 2020-07-17 09:43  睿晞  阅读(251)  评论(0编辑  收藏  举报