Hash算法,插入排序,希尔排序,选择排序,冒泡排序,归并排序,快速排序,堆排序,基数排序

Hash算法

hash就是散列表,就是把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值。

实质就是压缩映射,散列值的空间通常远小于输入的空间。

常利用hash算法,将输入的一千万个检索串转化为题目中所说大约三百万个不同的数,进行排序选出我们需要的值即可。

出现冲突时,可以用拉链法,就是用链表来解决冲突,用一个链表数组,来存储相应数据,当出现冲突时,依次添加到链表的后面进行处理。

Hash算法,插入排序,希尔排序,选择排序,冒泡排序,归并排序,快速排序,堆排序,基数排序_第1张图片

例题1 正方形

Hash算法,插入排序,希尔排序,选择排序,冒泡排序,归并排序,快速排序,堆排序,基数排序_第2张图片

基本思路就是,将输入的点存在数组和哈希表中,数组是为了顺序遍历,哈希表是为了查找快。

取正方形对角线上的两个顶点,根据几何关系计算另外一条对角线上。两个顶点,如果计算出的另外两个顶点都在map中,则找到一个正方形。

要注意的是,因为两条对角线各被计算了一次,所以结果要除以2。

已经知道对角线AC上的a,c坐标,求b点坐标的公式为:

bx=(ax+cx+cy-ay)/2;

by=(ay+cy+ax-cx)/2;

代码实现:

#include
using namespace std;
const int N = 1010;
const int H = 10007;
int ptx[N], pty[N], hashTable[H];
int cur, n;
long ans;
struct Node {
    int x;
    int y;
    int next;
}node[N];
void initHash() {
    for (int i = 0; i < H; i++) {
        hashTable[i] = -1;
    }
    cur = ans = 0;
}
void insertHash(int x, int y) {
    int h = (x * x + y * y) % H;//哈希函数
    node[cur].x = x;
    node[cur].y = y;
    node[cur].next = hashTable[h];
    hashTable[h] = cur++;
}
bool searchHash(int x, int y) {
    int h = (x * x + y * y) % H;
    int next = hashTable[h];
    while (next != -1) {
        if (x == node[next].x && y == node[next].y)
            return true;
        next = node[next].next;
    }
    return false;
}
int main() {
    iostream::sync_with_stdio(false);
    while (cin >> n && n != 0) {
        initHash();
        for (int i = 0; i < n; i++) {
            cin >> ptx[i] >> pty[i];
            insertHash(ptx[i], pty[i]);
        }
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                int x1 = ptx[i] - (pty[i] - pty[j]);
                int y1 = pty[i] + (ptx[i] - ptx[j]);
                int x2 = ptx[j] - (pty[i] - pty[j]);
                int y2 = pty[j] + (ptx[i] - ptx[j]);
                if (searchHash(x1, y1) && searchHash(x2, y2))
                    ans++;
            }
        }
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                int x1 = ptx[i] - (pty[i] - pty[j]);
                int y1 = pty[i] + (ptx[i] - ptx[j]);
                int x2 = ptx[j] - (pty[i] - pty[j]);
                int y2 = pty[j] + (ptx[i] - ptx[j]);
                if (searchHash(x1, y1) && searchHash(x2, y2))
                    ans++;
            }
        }
        ans >>= 2;
        cout << ans << endl;
    }

    return 0;
}

例题2 字符串哈希

Hash算法,插入排序,希尔排序,选择排序,冒泡排序,归并排序,快速排序,堆排序,基数排序_第3张图片

双重哈希,没用拉链法

代码实现:

#include
using namespace std;
void read(int& x) {
    x = 0;
    int f = 0;
    char ch = getchar();
    while (ch < '0' || ch>'9') {
        f |= (ch == '-');
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x = f ? -x : x;
    return;
}
const int maxn = 200020;
const int mod = 998244353;
const int p = 1e9 + 7;
int ans, n, cnt;
char str[maxn];
struct node {
    unsigned long long res, ress;
    unsigned long long hash(char* s, int len) {
        unsigned long long Ans = 0;
        for (int i = 1; i <= len; i++) {
            Ans = Ans * mod + s[i];
        }
        return Ans;
    }
    unsigned long long rehash(char* s, int len) {
        unsigned long long Ans = 0;
        for (int i = 1; i <= len; i++) {
            Ans = Ans * p + s[i];
        }
        return Ans;
    }
    bool operator<(const node& x) {
        return res == x.res ? ress < x.ress : res < x.res;
    }
}st[maxn];
int main() {
    iostream::sync_with_stdio(false);
    read(n);
    for (int i = 1; i <= n; i++) {
        cin >> str + 1;
        int len = strlen(str + 1);
        st[++cnt].res = st[i].hash(str + 1, len);
        st[++cnt].ress = st[i].rehash(str + 1, len);
    }
    sort(st + 1, st + 1 + cnt);
    for (int i = 1; i <= n; i++) {
        if (st[i].res == st[i + 1].res)
            if (st[i].ress == st[i + 1].ress)
                ans++;
    }
    cout << n - ans << endl;
    return 0;
}

插入排序

原理:将原数列中的第一个元素视为一个有序数列,视第二个元素至最后一个元素为未排序元素。从头到尾扫描整个未排序数列,然后将扫描到的每个元素插入到有序序列中的适当位置。

复杂度:最好可以达到O(n),最坏是O(n2),平均O(n2)

#include
using namespace std;
int main() {
    //全都是从小到大
    iostream::sync_with_stdio(false);
    int n;
    cin >> n;
    int* arr = new int[n];
    for (int i = 0; i < n; i++)cin >> arr[i];
    for (int i = 1; i < n; i++) {
        int temp = arr[i];
        int j;
        for (j = i - 1; j >= 0 && temp < arr[j]; j--)
            arr[j + 1] = arr[j];
        arr[j + 1] = temp;
    }
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }

    delete[]arr;
    return 0;
}

希尔排序

原理:选择一个增量序列,按照增量序列元素个数进行多次排序,每次排序根据对应的增量将待排序的数列分成若干个长度为m的子序列,分别对子表进行插入排序,当增量为1的时候,整个序列作为一个表来处理,表长度就是整个序列的长度。

复杂度:最好可以达到O(n1.3),最坏是O(n2),平均O(nlog2n)~O(n2)

#include
using namespace std;
int main() {
    //全都是从小到大
    iostream::sync_with_stdio(false);
    int n;
    cin >> n;
    int* arr = new int[n];
    for (int i = 0; i < n; i++)cin >> arr[i];
    for (int d = n / 2; d >= 1; d /= 2) {
        for (int i = d; i < n; i++) {
            int temp = arr[i];
            int j;
            for (j = i - d; j >= 0 && temp < arr[j]; j = j - d)
                arr[j + d] = arr[j];
            arr[j + d] = temp;
        }
    }
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }

    delete[]arr;
    return 0;
}

选择排序

复杂度:O(n2)

#include
using namespace std;
int main() {
    //全都是从小到大
    iostream::sync_with_stdio(false);
    int n;
    cin >> n;
    int* arr = new int[n];
    for (int i = 0; i < n; i++)cin >> arr[i];
    for (int i = 0; i < n - 1; i++) {
        int flag = i;
        for (int j = i + 1; j < n; j++)
            if (arr[flag] > arr[j]) flag = j;//选取最小值的下标
        if (flag != i) swap(arr[flag], arr[i]);
    }
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }

    delete[]arr;
    return 0;
}

冒泡排序

复杂度:最好可以达到O(n),最坏是O(n2),平均O(n2)

#include
using namespace std;
int main() {
    //全都是从小到大
    iostream::sync_with_stdio(false);
    int n;
    cin >> n;
    int* arr = new int[n];
    for (int i = 0; i < n; i++)cin >> arr[i];
    for (int i = 0; i < n; i++) {
        int flag = 0;
        for (int j = 0; j < n - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(arr[j], arr[j + 1]);
                flag = 1;
            }
        }
        if (flag == 0)break;
    }
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    delete[]arr;
    return 0;
}

归并排序(递归实现)

复杂度:O(nlog2n)

#include
using namespace std;
int datas[10];
void Merge(int first1, int last1, int last2) {
    int* temp = new int[10];
    int i = first1, j = last1 + 1, k = first1;
    while (i <=last1 && j <= last2) {
        if (datas[i] <= datas[j])temp[k++] = datas[i++];
        else temp[k++] = datas[j++];
    }
    while (i <= last1)temp[k++] = datas[i++];
    while (j <= last2)temp[k++] = datas[j++];
    for (i = first1; i <= last2; i++)datas[i] = temp[i];
    delete[]temp;
}
void MergeSort1(int first, int last) {
    if (first == last)return;
    else {
        int mid = (first + last) / 2;
        MergeSort1(first, mid);
        MergeSort1(mid + 1, last);
        Merge(first, mid, last);
    }
}
int main() {
    //全都是从小到大
    iostream::sync_with_stdio(false);
    for (int i = 0; i < 10; i++) {
        cin >> datas[i];
    }
    MergeSort1(0,9);
    for (int i = 0; i < 10; i++) {
        cout << datas[i] << " ";
    }
    return 0;
}

归并排序(非递归实现)

#include
using namespace std;
int datas[10];
int length = 10;
void Merge(int first1, int last1, int last2) {
    int* temp = new int[10];
    int i = first1, j = last1 + 1, k = first1;
    while (i <= last1 && j <= last2) {
        if (datas[i] <= datas[j])temp[k++] = datas[i++];
        else temp[k++] = datas[j++];
    }
    while (i <= last1)temp[k++] = datas[i++];
    while (j <= last2)temp[k++] = datas[j++];
    for (i = first1; i <= last2; i++)datas[i] = temp[i];
    delete[]temp;
}
void MergePass(int h) {
    int i = 0;
    while (i + 2 * h <= length) {
        Merge(i, i + h - 1, i + 2 * h - 1);
        i = i + 2 * h;
    }
    if (i + h < length) {
        Merge(i, i + h - 1, length - 1);
    }
}
void MergeSort2() {
    int h = 1;
    while (h < length) {
        MergePass(h);
        h = 2 * h;
    }
}

int main() {
    //全都是从小到大
    iostream::sync_with_stdio(false);
    for (int i = 0; i < 10; i++) {
        cin >> datas[i];
    }
    MergeSort2();
    for (int i = 0; i < 10; i++) {
        cout << datas[i] << " ";
    }
    return 0;
}

快速排序

复杂度:最好可以达到O(nlog2n),最坏是O(n2),平均O(nlog2n)

#include
using namespace std;
int datas[10];
int Partition(int first, int last) {
    int i = first, j = last;
    while (i < j) {
        while (i < j && datas[i] <= datas[j])j--;//右侧扫描
        if (i < j) {
            swap(datas[i], datas[j]);
            i++;
        }
        while (i < j && datas[i] <= datas[j])i++;//左侧扫描
        if (i < j) {
            swap(datas[i], datas[j]);
            j--;
        }

    }
    return i;
}
void QuickSort(int first, int last) {
    if (first >= last)return;//区间长度为1,递归结束
    else {
        int pivot = Partition(first, last);
        QuickSort(first, pivot-1);//对左侧子序列进行快速排序
        QuickSort(pivot + 1, last);//对右侧子序列进行快速排序

    }
}
int main() {
    //全都是从小到大
    iostream::sync_with_stdio(false);
    for (int i = 0; i < 10; i++) {
        cin >> datas[i];
    }
    QuickSort(0, 9);
    for (int i = 0; i < 10; i++) {
        cout << datas[i] << " ";
    }
    return 0;
}

基数排序

假设待排序序列记录看成是由d个子关键码复合而成,每个子关键码的取值范围为m个。

每一趟分配的时间复杂度是O(n),每一趟收集的时间复杂度为O(m),整个排序需要执行d趟。

复杂度:O(d(n+m)

#include
using namespace std;
struct Node {
    int data;
    Node* next;
};
void RadixSort(Node* first, int d) {
    Node* front[10], * rear[10], * tail;
    int i, j, k, base = 1;
    for (i = 1; i <= d; i++) {
        for (j = 0; j < 10; j++) {
            front[j] = rear[j] = NULL;
        }
        while (first != NULL) {
            k = (first->data / base) % 10;
            if (front[k] == NULL)front[k] = rear[k] = first;
            else rear[k] = rear[k]->next = first;
            first = first->next;
        }
        for (j = 0; j < 10; j++) {
            if (front[j] == NULL)continue;
            if (first == NULL)first = front[j];
            else tail->next = front[j];
            tail = rear[j];
        }
        tail->next = NULL;
        base = base * 10;
    }
}
int main() {
    iostream::sync_with_stdio(false);
    return 0;
}

堆排序

复杂度:O(nlog2n)

#include
using namespace std;
int datas[10];
int length = 10;
void Sift(int k, int last) {
    int i, j;
    i = k; j = 2 * i + 1;//i是被调整结点,j是i的左孩子
    while (j <= last) {
        if (j < last && datas[j] < datas[j + 1])j++;//j指向左右孩子的较大者
        if (datas[i] > datas[j])break;//已经是堆
        else {
            swap(datas[i], datas[j]);
            i = j; j = 2 * i + 1;//被调整结点位于结点j的位置
        }
    }
}
void HeapSort() {
    int i;
    for (i = length / 2 - 1; i >= 0; i--) {
        Sift(i, length - 1);
    }
    for (i = 1; i < length; i++) {
        swap(datas[0], datas[length - i]);
        Sift(0, length - i - 1);//重建堆
    }
}
int main() {
    //全都是从小到大
    iostream::sync_with_stdio(false);
    for (int i = 0; i < 10; i++) {
        cin >> datas[i];
    }
    HeapSort();
    for (int i = 0; i < 10; i++) {
        cout << datas[i] << " ";
    }
    return 0;
}

你可能感兴趣的:(算法,算法,哈希算法,数据结构)