# 排序

# 插入排序

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
// 打印数列 A
void print(int A[],int n) {
    for (int i = 0; i < n; i++)
        printf("%d%c", A[i], i == n - 1 ? '\n' : ' ');
}
// 插入排序法
void insertsort(int A[], int n) {
    // 从第二个开始,往前找比当前的小的值,
    // 比当前值大的就往后移,知道找到小于等于 A [i] 的
    for (int i = 1; i < n; i++) {
        int j = i - 1;
        int v = A[i];
        while (j >= 0 && A[j] > v) {
            A[j + 1] = A[j];
            j--;
        }
        A[j + 1] = v;
        print(A, n);
    }
}
int main() {
    int n, A[110];
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &A[i]);
    print(A, n);
    insertsort(A, n);
    return 0;
}

# 冒泡

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
// 冒泡排序法
int bubbleSort(int A[], int n) {
    int cnt = 0;
    // 标记是否需要继续冒泡
    int flag = 1;
    for (int i = 0; flag; i++) {
        flag = 0;
        for (int j = n - 1; j >= i + 1; j--) {
            // 交换两个相邻的元素
            if (A[j] < A[j - 1]) {
                swap(A[j], A[j - 1]);
                flag = 1;
                cnt++;
            }
        }
    }
    return cnt;
}
int main() {
    int n, A[110];
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &A[i]);
    int cnt = bubbleSort(A, n);
    for (int i = 0; i < n; i++)
        printf("%d%c", A[i], i == n - 1 ? '\n' : ' ');
    printf("%d\n", cnt);
    return 0;
}

# 选择

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
// 选择排序法
int selectionSort(int A[], int n) {
    int cnt = 0;
    for (int i = 0; i < n; i++) {
        int minj = i;
        for (int j = i; j < n; j++) {
            if (A[j] < A[minj])
                minj = j;
        }
        if (i != minj)
            swap(A[i], A[minj]), cnt++;
    }
    return cnt;
}
int main() {
    int n, A[110];
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &A[i]);
    int cnt = selectionSort(A, n);
    for (int i = 0; i < n; i++)
        printf("%d%c", A[i], i == n - 1 ? '\n' : ' ');
    printf("%d\n", cnt);
    return 0;
}

# 稳定

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
struct Card {
    char suit, value;
};
// 冒泡排序法
void bubble(struct Card A[], int n) {
    // 标记是否需要继续冒泡
    int flag = 1;
    for (int i = 0; flag; i++) {
        flag = 0;
        for (int j = n - 1; j >= i + 1; j--) {
            // 交换两个相邻的元素
            if (A[j].value < A[j - 1].value) {
                swap(A[j], A[j - 1]);
                flag = 1;
            }
        }
    }
}
// 选择排序法
void selection(struct Card A[], int n) {
    for (int i = 0; i < n; i++) {
        int minj = i;
        for (int j = i; j < n; j++) {
            if (A[j].value < A[minj].value)
                minj = j;
        }
        if (i != minj)
            swap(A[i], A[minj]);
    }
}
// 冒泡排序法是稳定排序,选择排序后的花色和其比较则可得知排序是否稳定的
bool isStable(struct Card C1[], struct Card C2[], int n) {
    for (int i = 0; i < n; i++) {
        if (C1[i].suit != C2[i].suit)
            return false;
    }
    return true;
}
// 打印输出
void print(struct Card C[], int n) {
    for (int i = 0; i < n; i++) {
        printf("%c%c%c", C[i].suit, C[i].value, i == n - 1 ? '\n' : ' ');
    }
}
int main() {
    Card C1[100], C2[100];
    int n;
    scanf("%d", &n);
    getchar();
    for (int i = 0; i < n; i++) {
        scanf("%c%c", &C1[i].suit, &C1[i].value);
        getchar();
        C2[i] = C1[i];
    }
    // 对于 C1 数列进行冒泡排序,对 C2 数列进行选择排序,然后比较两者排序后的花色
    // 则可得知选择排序是否稳定
    bubble(C1, n);
    selection(C2, n);
    print(C1, n);
    printf("Stable\n");
    print(C2, n);
    if (isStable(C1, C2, n))
        printf("Stable\n");
    else
        printf("Not stable\n");
    return 0;
}

# 希尔

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
//g 数组
vector<int>G;
long long cnt;
int A[1000000 + 10];
// 间隔为 g 的插入排序
void insertionSort(int A[], int n, int g) {
    for (int i = g; i < n; i++) {
        int v = A[i];
        int j = i - g;
        while (j >= 0 && A[j] > v) {
            A[j + g] = A[j];
            j -= g;
            cnt++;
        }
        A[j + g] = v;
    }
}
// 希尔排序
void shellsort(int A[], int n) {
    for (int i = G.size() - 1; i >= 0; i--) {
        insertionSort(A, n, G[i]);
    }
}
// 生成 g 数组
void getArray(int n) {
    for (int h = 1; h <= n;) {
        G.push_back(h);
        h = 3 * h + 1;
    }
}
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &A[i]);
    getArray(n);
    shellsort(A,n);
    int len = G.size();
    printf("%d\n", len);
    for (int i = len - 1; i >= 0; i--)
        printf("%d%c", G[i], i == 0 ? '\n' : ' ');
    printf("%lld\n", cnt);
    for (int i = 0; i < n; i++)
        printf("%d\n", A[i]);
    return 0;
}

# 数据结构

#

/* 实现栈的功能 */
#include<iostream>
#include<cstdio>
using namespace std;
// 实现栈的功能
//top 是指向栈顶的指针, s 是实现栈结构的数组
int top, S[1000];
// 将 x 压入栈的操作
void push(int x) {
    //top 加 1 之后将元素插入到 top 所指的位置
    S[++top] = x;
}
// 将栈顶元素返回并删除
int pop() {
    top--;
    return S[top + 1];
}
// 字符转数字
int CharToInt(char s[]) {
    int ans = 0, i = 0;
    while (s[i] != '\0') {
        ans = ans * 10 + s[i] - '0';
        i++;
    }
    return ans;
}
int main() {
    char s[1000];
    int a, b;
    // 清空栈
    top = 0; 
    while(scanf("%s",s)!=EOF){
            if (s[0] == '+') {
                b = pop();a = pop();
                push(a + b);
            }else if (s[0] == '-') {
                b = pop(); a = pop();
                push(a - b);
            }else if (s[0] == '*') {
                b = pop(); a = pop();
                push(a * b);
            }else {
                push(CharToInt(s));
            }
    }
    printf("%d\n",pop());
    return 0;
}

# 队列

/* 实现队列功能 */
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxx = 100000 + 10;
struct task {
    // 任务的名字和耗费的时间
    char name[100];
    int t;
};
task Queue[maxx];
// 指向队头和队尾的指针
int head, tail;
// 判断循环队列是否已满
bool isFull() {
    return head == (tail + 1) % maxx;
}
// 判断循环队列是否为空
bool isEmpty() {
    return head == tail;
}
// 将元素 x 添加到队列的末尾
void enqueue(task x) {
    Queue[tail] = x;
    // 循环队列
    tail = (tail + 1) % maxx;
}
// 返回队头元素并删除
task dequeue() {
    task x = Queue[head];
    // 循环队列
    head = (head + 1) % maxx;
    return x;
}
int main() {
    int n, q;
    scanf("%d %d", &n, &q);
    for (int i = 0; i < n; i++) {
        scanf("%s %d", Queue[i].name, &Queue[i].t);
    }
    // 当前已经有 n 个元素
    head = 0; tail = n;
    // 当前时间
    int nowtime = 0;
    while (!isEmpty()) {
        // 取出队头
        task u = dequeue();
        // 执行时间片 p 和 所需要时间 u.t
        int c = min(q, u.t);
        // 任务执行了 c ms
        u.t -= c;
        // 当前时间加上 c ms
        nowtime += c;
        // 任务还没做完,加入到队尾
        if (u.t > 0) {
            enqueue(u);
        }
        else { // 任务已经完成,打印出结果
            printf("%s %d\n", u.name, nowtime);
        }
    }
    return 0;
}

# 链表

/* 实现双向链表功能 */
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int maxx = 100000 + 10;
struct Node {
    int key;
    Node *prev, *next;
};
Node *nil;
// 链表初始化
void init() {
    nil = (Node *)malloc(sizeof(Node));
    //C++ nil = new Node();
    nil->next = nil;
    nil->prev = nil;
}
// 从链表搜索出值为 key 的结点 O (n)
Node* listSearch(int key) {
    // 从链表头结点开始访问
    Node *cur = nil->next;
    while (cur != nil && cur->key != key) {
        cur = cur->next;
    }
    return cur;
}
// 打印链表
void printList() {
    Node *cur = nil->next;
    int flag = 0;
    while (cur != nil) {
        if (flag++ > 0)
            printf(" ");
        printf("%d", cur->key);
        cur = cur->next;
    }
    printf("\n");
}
// 删除结点 t
void deleteNode(Node *t) {
    //t 为头结点不做处理
    if (t == nil)
        return;
    t->prev->next = t->next;
    t->next->prev = t->prev;
    free(t);
    //C++ delete(t);
}
// 删除头结点
void deleteFirst() {
    deleteNode(nil->next);
}
// 删除尾结点
void deleteLast() {
    deleteNode(nil->prev);
}
// 删除指定的 key O (n)
void deleteKey(int key) {
    deleteNode(listSearch(key));
}
// 在链表头部添加元素 key
void insert(int key) {
    Node *x = (Node *)malloc(sizeof(Node));
    //C++ Node *x = new Node();
    x->key = key;
    x->next = nil->next;
    nil->next->prev = x;
    nil->next = x;
    x->prev = nil;
}
int main() {
    int n, key, size = 0;
    char op[20];
    scanf("%d", &n);
    getchar();
    // 初始化链表
    init();
    for (int i = 0; i < n; i++) {
        scanf("%s %d", op, &key);
        if (op[0] == 'i') {
            insert(key);
            size++;
        }
        else {
            if (strlen(op) > 6) {
                if (op[6] == 'F') {// 删除头结点
                    deleteFirst();
                }
                else {// 删除尾结点
                    deleteLast();
                }
            }
            else { // 删除结点
                deleteKey(key);
            }
            size--;
        }
    }
    printList();
    return 0;
}

# 标准库

/* 利用 STL 的 stack 类 */
#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
// 字符转数字
int CharToInt(char s[]) {
    int ans = 0, i = 0;
    while (s[i] != '\0') {
        ans = ans * 10 + s[i] - '0';
        i++;
    }
    return ans;
}
int main() 
{
    char s[1000];
    int a, b;
    stack<int> S;
    while(scanf("%s",s)!=EOF){
            if (s[0] == '+') {
                b = S.top(); S.pop();
                a = S.top(); S.pop();
                S.push(a + b);
            }else if (s[0] == '-') {
                b = S.top(); S.pop();
                a = S.top(); S.pop();
                S.push(a - b);
            }else if (s[0] == '*') {
                b = S.top(); S.pop();
                a = S.top(); S.pop();
                S.push(a * b);
            }else {
                S.push(CharToInt(s));
            }
    }
    printf("%d\n", S.top());
    return 0;
}
/* 利用 STL 的 stack 类 */
#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
// 字符转数字
int CharToInt(char s[]) {
    int ans = 0, i = 0;
    while (s[i] != '\0') {
        ans = ans * 10 + s[i] - '0';
        i++;
    }
    return ans;
}
int main() 
{
    char s[1000];
    int a, b;
    stack<int> S;
    while(scanf("%s",s)!=EOF){
            if (s[0] == '+') {
                b = S.top(); S.pop();
                a = S.top(); S.pop();
                S.push(a + b);
            }else if (s[0] == '-') {
                b = S.top(); S.pop();
                a = S.top(); S.pop();
                S.push(a - b);
            }else if (s[0] == '*') {
                b = S.top(); S.pop();
                a = S.top(); S.pop();
                S.push(a * b);
            }else {
                S.push(CharToInt(s));
            }
    }
    printf("%d\n", S.top());
    return 0;
}
/* 利用 STL 的 list 类 */
#include<iostream>
#include<cstdio>
#include<cstring>
#include<list>
using namespace std;
int main() {
    int n, key;
    char op[20];
    list<int> List;
    scanf("%d", &n);
    getchar();
    for (int i = 0; i < n; i++) {
        scanf("%s %d", op, &key);
        if (op[0] == 'i') {
            List.push_front(key);
        }
        else {
            if (strlen(op) > 6) {
                if (op[6] == 'F') {// 删除头结点
                    List.pop_front();
                }
                else {// 删除尾结点
                    List.pop_back();
                }
            }
            else { // 删除结点
                for (list<int>::iterator it = List.begin(); it != List.end(); it++) {
                    if (*it == key) {
                        List.erase(it);
                        break;
                    }
                }
            }
        }
    }
    int flag = 0;
    for (list<int>::iterator it = List.begin(); it != List.end(); it++) {
        if (flag != 0)
            printf(" ");
        flag++;
        printf("%d", (*it));
    }
    printf("\n");
    return 0;
}

# 搜索

# 线性

#include<iostream>
#include<cstdio>
using namespace std;
// 线性搜索
bool LinearSearch(int A[], int n, int key) {
    // 将 key 设置为数列最后一项
    A[n] = key;
    int i = 0;
    while (A[i] != key)
        i++;
    // 如果 i 不是 n,则代表在原来的数列中找到 key,
    // 否则代表原来数列中没有 key,找到的是刚才插入到最后的元素
    return i != n;
}
int main() {
    int n, q, key;
    int sum = 0;
    int A[10000 + 10];
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &A[i]);
    scanf("%d", &q);
    for (int i = 0; i < q; i++) {
        scanf("%d", &key);
        if (LinearSearch(A, n, key))
            sum++;
    }
    printf("%d\n", sum);
}

# 二分

/* 实现二分搜索 */
#include<iostream>
#include<cstdio>
using namespace std;
// 二分搜索
bool BinarySearch(int A[], int n, int key) {
    int left = 0 , right = n, mid;
    while (left < right) {
        mid = (left + right) / 2;
        if (key == A[mid])
            return true;
        if(key > A[mid])
            left = mid + 1;
        if (key < A[mid])
            right = mid;
    }
    return false;
}
int main() {
    int n, q, key;
    int sum = 0;
    int A[100000 + 10];
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &A[i]);
    scanf("%d", &q);
    for (int i = 0; i < q; i++) {
        scanf("%d", &key);
        if (BinarySearch(A, n, key))
            sum++;
    }
    printf("%d\n", sum);
}

# 散列

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const LL maxx = 1000000 + 10;
char H[maxx][15];
// 将字符转换为数值
LL CharToInt(char ch) {
    if (ch == 'A') return 1;
    if (ch == 'C') return 2;
    if (ch == 'G') return 3;
    if (ch == 'T') return 4;
    return 0;
}
// 将字符串转成数值并生成 key
long long getKey(char str[]) {
    LL sum = 0, p = 1;
    LL len = strlen(str);
    for (long long int i = 0; i < len; i++) {
        sum += p * CharToInt(str[i]);
        p *= 5;
    }
    return sum;
}
LL h1(LL key) {
    return key % maxx;
}
LL h2(LL key) {
    return 1 + (key % (maxx - 1));
}
//find 操作
bool find(char str[]) {
    LL key, h;
    key = getKey(str);
    for (LL i = 0;; i++) {
        h = (h1(key) + i * h2(key)) % maxx;
        // 找到 key
        if (strcmp(H[h], str) == 0) return true;
        //key 不存在
        else if (strlen(H[h]) == 0) return false;
    }
    return false;
}
//insert 操作
void insert(char str[]) {
    LL key, h;
    key = getKey(str);
    for (LL i = 0;; i++) {
        h = (h1(key) + i * h2(key)) % maxx;
        // 找到 key
        if (strcmp(H[h], str) == 0) return ;
        //key 不存在
        else if (strlen(H[h]) == 0) {
            // 插入
            strcpy(H[h], str);
            return ;
        }
    }
}
int main() {
    int n, q, key;
    char str[20], op[20];
    for (int i = 0; i < maxx; i++)
        H[i][0] = '\0';
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%s %s", op, str);
        if (op[0] == 'i')
            insert(str);
        else {
            if (find(str))
                printf("yes\n");
            else
                printf("no\n");
        }
    }
    return 0;
}

# 标准库

/* 利用 STL 的 binary_search*/
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int main() {
    int n, q, key;
    int sum = 0;
    int A[100000 + 10];
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &A[i]);
    scanf("%d", &q);
    for (int i = 0; i < q; i++) {
        scanf("%d", &key);
        if (binary_search(A, A + n, key))
            sum++;
    }
    printf("%d\n", sum);
}

# 递归 & 分治

# 穷竭搜索

#include<iostream>
#include<cstdio>
using namespace std;
int n, A[30];
// 递归穷举
bool solve(int i, int m) {
    // 已经找到得到 m 的组合方式
    if (m == 0)
        return true;
    // 已经穷举过 A 的全部元素了
    if (i >= n)
        return false;
    // 分别穷举 不选 A [i] 和 选择 A [i] 的情况
    return solve(i + 1, m) || solve(i + 1, m - A[i]);
}
int main(){
    int t, M;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &A[i]);
    }
    scanf("%d", &t);
    for (int i = 0; i < t; i++) {
        scanf("%d", &M);
        if (solve(0, M))
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;
}

# 科赫曲线

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const double PI = acos(-1.0);
struct Point{
    double x,y;
};
void koch(int n, Point a, Point b) {
    // 递归结束
    if (n == 0)
        return;
    // 三等分点 s,t ,(u 是 s,t 上方的点)
    Point s, t, u;
    // 角度从度转成弧度
    double th = PI * 60.0 / 180.0;
    s.x = (2.0 * a.x + 1.0 * b.x) / 3.0;
    s.y = (2.0 * a.y + 1.0 * b.y) / 3.0;
    t.x = (1.0 * a.x + 2.0 * b.x) / 3.0;
    t.y = (1.0 * a.y + 2.0 * b.y) / 3.0;
    u.x = (t.x - s.x) * cos(th) - (t.y - s.y) * sin(th) + s.x;
    u.y = (t.x - s.x) * sin(th) + (t.y - s.y) * cos(th) + s.y;
    koch(n - 1, a, s);
    printf("%.8lf %.8lf\n", s.x, s.y);
    koch(n - 1, s, u);
    printf("%.8lf %.8lf\n", u.x, u.y);
    koch(n - 1, u, t);
    printf("%.8lf %.8lf\n", t.x, t.y);
    koch(n - 1, t, b);
}
int main(){
    Point a, b;
    int n;
    scanf("%d", &n);
    // 初始化
    a.x = a.y = 0;
    b.x = 100, b.y = 0;
    printf("%.8lf %.8lf\n", a.x, a.y);
    koch(n, a, b);
    printf("%.8lf %.8lf\n", b.x, b.y);
    return 0;
}

# 高等排序

# 归并

#include<iostream>
#include<cstdio>
using namespace std;
const int MAX = 500000;
const int maxnum = 1000000010;
// 两个局部数组
int L[MAX / 2 + 2], R[MAX / 2 + 2];
int A[MAX], n;
int cnt = 0;
// 排序和合并
void merge(int left, int mid, int right) {
    int n1 = mid - left;
    int n2 = right - mid;
    for (int i = 0; i < n1; i++) L[i] = A[left + i];
    for (int i = 0; i < n2; i++) R[i] = A[mid + i];
    // 两个局部数组最后添加一个比较大的数
    L[n1] = R[n2] = maxnum;
    int i = 0, j = 0;
    // 合并
    for (int k = left; k < right; k++) {
        cnt++;
        if (L[i] <= R[j])
            A[k] = L[i++];
        else
            A[k] = R[j++];
    }
}
// 分割
void mergeSort(int left, int right) {
    if (left + 1 < right) {
        int mid = (left + right) / 2;
        mergeSort(left, mid);
        mergeSort(mid, right);
        merge(left, mid, right);
    }
}
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &A[i]);
    mergeSort(0, n);
    for (int i = 0; i < n; i++)
        printf("%d%c", A[i], i == n - 1 ? '\n' : ' ');
    printf("%d\n", cnt);
    return 0;
}

# 分割

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX = 500000;
int A[MAX], n;
// 分割
int partition(int p, int r) {
    int x = A[r];
    int i = p - 1;
    for (int j = p; j < r; j++) {
        if (A[j] <= x) {
            i++;
            swap(A[i], A[j]);
        }
    }
    swap(A[i + 1], A[r]);
    return i + 1;
}
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &A[i]);
    // 记录 Ar 的下标
    int p = partition(0, n - 1);
    for (int i = 0; i < n; i++) {
        if(i == p)
            printf("[%d]%c", A[i], i == n - 1 ? '\n' : ' ');
        else
            printf("%d%c", A[i], i == n - 1 ? '\n' : ' ');
    }
    return 0;
}

# 快排

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX = 500000;
int A[MAX], n;
// 分割
int partition(int p, int r) {
    int x = A[r];
    int i = p - 1;
    for (int j = p; j < r; j++) {
        if (A[j] <= x) {
            i++;
            swap(A[i], A[j]);
        }
    }
    swap(A[i + 1], A[r]);
    return i + 1;
}
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &A[i]);
    // 记录 Ar 的下标
    int p = partition(0, n - 1);
    for (int i = 0; i < n; i++) {
        if(i == p)
            printf("[%d]%c", A[i], i == n - 1 ? '\n' : ' ');
        else
            printf("%d%c", A[i], i == n - 1 ? '\n' : ' ');
    }
    return 0;
}

# 计数

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxx = 2000001;
const int maxnum = 10010;
int A[maxx], B[maxx];
int C[maxnum];
int main() {
    int n;
    scanf("%d", &n);
    // 初始化 C 数组
    for (int i = 0; i < maxnum; i++)
        C[i] = 0;
    for (int i = 0; i < n; i++) {
        scanf("%d", &A[i + 1]);
        // 计数到 C 数组
        C[A[i + 1]]++;
    }
    // 累加和
    for (int i = 1; i < maxnum; i++)
        C[i] += C[i - 1];
    for (int j = 1; j <= n; j++) {
        // 根据 C [A [j]] 确定 A [j] 存贮的下标,保存到 B 数组
        B[C[A[j]]] = A[j];
        // 存储下标往前移动
        C[A[j]] --;
    }
    for (int i = 1; i <= n; i++)
        printf("%d%c", B[i], i == n ? '\n' : ' ');
    return 0;
}

# 标准库


#

# 有根数

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAX = 100005;
const int NIL = -1;
struct Node {
    int p, l, r;
};
Node Tree[MAX];
int n, Depth[MAX];
void print(int u) {
    printf("node %d: ", u);
    printf("parent = %d, ", Tree[u].p);
    printf("depth = %d, ", Depth[u]);
    if (Tree[u].p == NIL)
        printf("root, ");
    else if (Tree[u].l == NIL)
        printf("leaf, ");
    else
        printf("internal node, ");
    printf("[");
    // 从子结点的最左边开始遍历
    int c = Tree[u].l;
    while (c != NIL) {
        printf("%d", c);
        if (Tree[c].r != NIL)
            printf(", ");
        // 跳到右侧紧邻的兄弟结点
        c = Tree[c].r;
    }
    printf("]\n");
}
// 递归得求深度
void rec(int u, int depth) {
    Depth[u] = depth;
    if (Tree[u].r != NIL)  // 右侧兄弟设置为相同深度
        rec(Tree[u].r, depth);
    if (Tree[u].l != NIL)  // 最左侧子结点的深度设置为自己的深度 + 1
        rec(Tree[u].l, depth + 1);
}
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        Tree[i].p = Tree[i].l = Tree[i].r = NIL;
    }
    int v, num, c, l, root;
    for (int i = 0; i < n; i++) {
        //v 是当前结点值 ,num 是 v 结点的子结点数 
        scanf("%d %d", &v, &num);
        for (int j = 0; j < num; j++) {
            scanf("%d", &c);
            // 设置最左侧结点 和 紧邻右侧兄弟结点
            //l 记录的是上一个结点,将当前的结点设置为 l 的紧邻右侧结点
            if (j == 0)
                Tree[v].l = c;
            else
                Tree[l].r = c;
            l = c;
            // 设置父结点
            Tree[c].p = v;
        }
    }
    // 找出根结点
    for (int i = 0; i < n; i++) {
        if (Tree[i].p == NIL)
            root = i;
    }
    rec(root, 0);
    for (int i = 0; i < n; i++)
        print(i);
    return 0;
}

# 二叉树

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAX = 100005;
const int NIL = -1;
struct Node {
    int parent, left, right;
};
Node Tree[MAX];
int n, Depth[MAX], Height[MAX];
int getDegree(int u) {
    int deg = 0;
    if (Tree[u].left != NIL)
        deg++;
    if (Tree[u].right != NIL)
        deg++;
    return deg;
}
void setDepth(int u, int depth) {
    if (u == NIL)
        return;
    Depth[u] = depth;
    setDepth(Tree[u].left, depth + 1);
    setDepth(Tree[u].right, depth + 1);
}
int setHeight(int u) {
    int h1 = 0, h2 = 0;
    if (Tree[u].left != NIL)
        h1 = setHeight(Tree[u].left) + 1;
    if (Tree[u].right != NIL)
        h2 = setHeight(Tree[u].right) + 1;
    return Height[u] = max(h1, h2);
}
int getSibling(int u) {
    if (Tree[u].parent == NIL)
        return NIL;
    // 存在左兄弟
    if (Tree[Tree[u].parent].left != u && Tree[Tree[u].parent].left != NIL)
        return Tree[Tree[u].parent].left;
    // 存在右兄弟
    if (Tree[Tree[u].parent].right != u && Tree[Tree[u].parent].right != NIL)
        return Tree[Tree[u].parent].right;
    return NIL;
}
void print(int u) {
    printf("node %d: parent = %d, sibling = %d, degree = %d, depth = %d, height = %d, "
        , u, Tree[u].parent, getSibling(u), getDegree(u), Depth[u], Height[u]);
    if (Tree[u].parent == NIL)
        printf("root\n");
    else if (Tree[u].left != NIL || Tree[u].right != NIL)
        printf("internal node\n");
    else
        printf("leaf\n");
}
int main() {
    int n;
    int u, l, r, root;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        Tree[i].parent = Tree[i].left = Tree[i].right = NIL;
    }
    for (int i = 0; i < n; i++) {
        scanf("%d %d %d", &u, &l, &r);
        Tree[u].left = l;
        Tree[u].right = r;
        Tree[l].parent = u;
        Tree[r].parent = u;
    }
    for (int i = 0; i < n; i++) {
        if (Tree[i].parent == NIL)
            root = i;
    }
    setHeight(root);
    setDepth(root, 0);
    for (int i = 0; i < n; i++)
        print(i);
    return 0;
}

# 树的遍历

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAX = 100005;
const int NIL = -1;
struct Node {
    int parent, left, right;
};
Node Tree[MAX];
int n;
// 前序排序
void PreorderTreeWalk(int u) {
    if (u == NIL)
        return;
    printf(" %d", u);
    PreorderTreeWalk(Tree[u].left);
    PreorderTreeWalk(Tree[u].right);
}
// 中序排序
void InorderTreeWalk(int u) {
    if (u == NIL)
        return;
    InorderTreeWalk(Tree[u].left);
    printf(" %d", u);
    InorderTreeWalk(Tree[u].right);
}
// 后序排序
void PostorderTreeWalk(int u) {
    if (u == NIL)
        return;
    PostorderTreeWalk(Tree[u].left);
    PostorderTreeWalk(Tree[u].right);
    printf(" %d", u);
}
int main() {
    int n;
    int u, l, r, root;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        Tree[i].parent = Tree[i].left = Tree[i].right = NIL;
    }
    for (int i = 0; i < n; i++) {
        scanf("%d %d %d", &u, &l, &r);
        Tree[u].left = l;
        Tree[u].right = r;
        Tree[l].parent = u;
        Tree[r].parent = u;
    }
    for (int i = 0; i < n; i++) {
        if (Tree[i].parent == NIL)
            root = i;
    }
    printf("Preorder\n");
    PreorderTreeWalk(root);
    printf("\nInorder\n");
    InorderTreeWalk(root);
    printf("\nPostorder\n");
    PostorderTreeWalk(root);
    printf("\n");
    return 0;
}

# 树的重建

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
vector<int> pre, in, post;
int pos;
int n, k;
void reconstruction(int left, int right) {
    // 遍历到叶结点
    if (left >= right)
        return;
    // 当前子树的根
    int root = pre[pos++];
    // 找出当前根的值在中序数组里的下标
    int m = distance(in.begin(), find(in.begin(), in.end(), root));
    reconstruction(left, m);
    reconstruction(m + 1, right);
    // 存入到后序数组
    post.push_back(root);
}
void solve() {
    pos = 0;
    reconstruction(0, pre.size());
    for (int i = 0; i < n; i++) {
        printf("%d%c", post[i], i == n-1?'\n':' ');
    }
}
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &k);
        pre.push_back(k);
    }
    for (int i = 0; i < n; i++) {
        scanf("%d", &k);
        in.push_back(k);
    }
    solve();
    return 0;
}

# 二叉搜索树

# 二叉搜索树

#include<iostream>
#include<cstdio>
using namespace std;
const int MAX = 100005;
struct Node {
    int key;
    Node *parent, *left, *right;
};
Node *root, *NIL;
// 前序排序
void PreorderTreeWalk(Node *u) {
    if (u == NIL)
        return;
    printf(" %d", u->key);
    PreorderTreeWalk(u->left);
    PreorderTreeWalk(u->right);
}
// 中序排序
void InorderTreeWalk(Node *u) {
    if (u == NIL)
        return;
    InorderTreeWalk(u->left);
    printf(" %d", u->key);
    InorderTreeWalk(u->right);
}
void insert(int value) {
    Node *y = NIL, *x = root;
    Node *z = new Node();
    z->key = value;
    z->left = z->right = NIL;
    // 从根结点往下遍历
    while (x != NIL) {
        y = x;
        //z 比 x 小, 则从 x 的左侧遍历
        //z 比 x 大, 则从 x 的右侧遍历
        if (z->key < x->key)
            x = x->left;
        else
            x = x->right;
    }
    z->parent = y;
    // 没有父结点的是 root
    if (y == NIL) {
        root = z;
    }else {
        //z 比 y 小, 则在 y 的左侧
        //z 比 y 大, 则在 y 的右侧
        if (z->key < y->key)
            y->left = z;
        else
            y->right = z;
    }
}
int main() {
    int n, value;
    char s[200];
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%s", s);
        if (s[0] == 'i') {
            scanf("%d", &value);
            insert(value);
        }else {
            InorderTreeWalk(root);
            printf("\n");
            PreorderTreeWalk(root);
            printf("\n");
        }
    }
    return 0;
}
#include<iostream>
#include<cstdio>
using namespace std;
const int MAX = 100005;
struct Node {
    int key;
    Node *parent, *left, *right;
};
Node *root, *NIL;
// 前序排序
void PreorderTreeWalk(Node *u) {
    if (u == NIL)
        return;
    printf(" %d", u->key);
    PreorderTreeWalk(u->left);
    PreorderTreeWalk(u->right);
}
// 中序排序
void InorderTreeWalk(Node *u) {
    if (u == NIL)
        return;
    InorderTreeWalk(u->left);
    printf(" %d", u->key);
    InorderTreeWalk(u->right);
}
void insert(int value) {
    Node *y = NIL, *x = root;
    Node *z = new Node();
    z->key = value;
    z->left = z->right = NIL;
    // 从根结点往下遍历
    while (x != NIL) {
        y = x;
        //z 比 x 小, 则从 x 的左侧遍历
        //z 比 x 大, 则从 x 的右侧遍历
        if (z->key < x->key)
            x = x->left;
        else
            x = x->right;
    }
    z->parent = y;
    // 没有父结点的是 root
    if (y == NIL) {
        root = z;
    }else {
        //z 比 y 小, 则在 y 的左侧
        //z 比 y 大, 则在 y 的右侧
        if (z->key < y->key)
            y->left = z;
        else
            y->right = z;
    }
}
Node * find(Node *u, int value) {
    // 从根结点开始遍历下去
    while (u != NIL && u->key != value) {
        if (value < u->key)
            u = u->left;
        else
            u = u->right;
    }
    return u;
}
int main() {
    int n, value;
    Node * f;
    char s[200];
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%s", s);
        if (s[0] == 'i') {
            scanf("%d", &value);
            insert(value);
        }
        else if (s[0] == 'f') {
            scanf("%d", &value);
            f = find(root,value);
            if (f != NIL)
                printf("yes\n");
            else
                printf("no\n");
        }else {
            InorderTreeWalk(root);
            printf("\n");
            PreorderTreeWalk(root);
            printf("\n");
        }
    }
    return 0;
}
#include<iostream>
#include<cstdio>
using namespace std;
const int MAX = 100005;
struct Node {
    int key;
    Node *parent, *left, *right;
};
Node *root, *NIL;
// 前序排序
void PreorderTreeWalk(Node *u) {
    if (u == NIL)
        return;
    printf(" %d", u->key);
    PreorderTreeWalk(u->left);
    PreorderTreeWalk(u->right);
}
// 中序排序
void InorderTreeWalk(Node *u) {
    if (u == NIL)
        return;
    InorderTreeWalk(u->left);
    printf(" %d", u->key);
    InorderTreeWalk(u->right);
}
void insert(int value) {
    Node *y = NIL, *x = root;
    Node *z = new Node();
    z->key = value;
    z->left = z->right = NIL;
    // 从根结点往下遍历
    while (x != NIL) {
        y = x;
        //z 比 x 小, 则从 x 的左侧遍历
        //z 比 x 大, 则从 x 的右侧遍历
        if (z->key < x->key)
            x = x->left;
        else
            x = x->right;
    }
    z->parent = y;
    // 没有父结点的是 root
    if (y == NIL) {
        root = z;
    }
    else {
        //z 比 y 小, 则在 y 的左侧
        //z 比 y 大, 则在 y 的右侧
        if (z->key < y->key)
            y->left = z;
        else
            y->right = z;
    }
}
Node * find(Node *u, int value) {
    // 从根结点开始遍历下去
    while (u != NIL && u->key != value) {
        if (value < u->key)
            u = u->left;
        else
            u = u->right;
    }
    return u;
}
// 树的最小值
Node *treeMinimum(Node * x) {
    while (x->left != NIL)
        x = x->left;
    return x;
}
//case 3 , 搜索后一个结点
Node *treeSuccessor(Node *x) {
    if (x->right != NIL)
        return treeMinimum(x->right);
    Node *y = x->parent;
    while (y != NIL && x == y->right) {
        x = y;
        x = y->parent;
    }
    return y;
}
void treeDelete(Node * z) {
    Node *y, *x;  // 要删除的对象和 y 的子结点
    // 确定要删除的结点
    if (z->left == NIL || z->right == NIL)
        y = z;
    else
        y = treeSuccessor(z);
    // 确定 y 的子结点 x
    if (y->left != NIL)
        x = y->left;
    else
        x = y->right;
    // 让子结点链接父结点
    if (x != NIL)
        x->parent = y->parent;
    // 让父结点链接子结点
    if (y->parent == NIL)
        root = x;
    else {
        if (y == y->parent->left)
            y->parent->left = x;
        else
            y->parent->right = x;
    }
    // case 3
    if (y != z)
        z->key = y->key;
    delete y;
}
int main() {
    int n, value;
    Node * f;
    char s[200];
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%s", s);
        if (s[0] == 'i') {
            scanf("%d", &value);
            insert(value);
        }
        else if (s[0] == 'f') {
            scanf("%d", &value);
            f = find(root, value);
            if (f != NIL)
                printf("yes\n");
            else
                printf("no\n");
        }
        else if (s[0] == 'd') {
            scanf("%d", &value);
            treeDelete(find(root, value));
        }
        else {
            InorderTreeWalk(root);
            printf("\n");
            PreorderTreeWalk(root);
            printf("\n");
        }
    }
    return 0;
}

#

# 完全二叉堆

#include <iostream>
#include <cstdio>
using namespace std;
// 分别求出结点 i 的父结点,左子结点、右子结点
int parent(int i) { return i / 2; }
int left(int i) { return 2 * i; }
int right(int i) { return 2 * i + 1; }
int main()
{
    int H[300];
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &H[i]);
    for (int i = 1; i <= n; i++) {
        printf("node %d: key = %d, ", i, H[i]);
        if (parent(i) >= 1)
            printf("parent key = %d, ", H[parent(i)]);
        if (left(i) <= n) 
            printf("left key = %d, ", H[left(i)]);
        if (right(i) <= n)
            printf("right key = %d, ", H[right(i)]);
        printf("\n");
    }
    return 0;
}

# 最大堆

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxx = 2000000;
int A[maxx + 1];
int n;
void maxHeapify(int i) {
    int left = 2 * i, right = 2 * i + 1;
    int largest;
    // 从左子结点、自身、右子结点选出值最大的结点,然后继续往下递归
    if (left <= n && A[left] > A[i])
        largest = left;
    else
        largest = i;
    if (right <= n && A[right] > A[largest])
        largest = right;
    if (largest != i) {
        swap(A[i], A[largest]);
        maxHeapify(largest);
    }
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &A[i]);
    for (int i = n / 2; i >= 1; i--)
        maxHeapify(i);
    for (int i = 1; i <= n; i++)
        printf(" %d", A[i]);
    printf("\n");
    return 0;
}

# 优先队列

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxx = 2000000;
const int INF = 1 << 30;
int A[maxx + 1];
int n;
void maxHeapify(int i) {
    int left = 2 * i, right = 2 * i + 1;
    int largest;
    // 从左子结点、自身、右子结点选出值最大的结点,然后继续往下递归
    if (left <= n && A[left] > A[i])
        largest = left;
    else
        largest = i;
    if (right <= n && A[right] > A[largest])
        largest = right;
    if (largest != i) {
        swap(A[i], A[largest]);
        maxHeapify(largest);
    }
}
int extract() 
{
    int maxv;
    if (n < 1)
        return -INF;
    maxv = A[1];
    A[1] = A[n--];
    maxHeapify(1);
    return maxv;
}
int insert(int key) {
    n++;
    int i = n;
    A[n] = -INF;
    if (key < A[i])
        return -INF;
    A[i] = key;
    while (i > 1 && A[i / 2] < A[i]) {
        swap(A[i], A[i / 2]);
        i /= 2;
    }
}
int main()
{
    char op[20];
    int k;
    while (scanf("%s", op) != EOF&&op[2] != 'd') {
        if (op[0] == 'i') {
            scanf("%d", &k);
            insert(k);
        }
        else {
            printf("%d\n", extract());
        }
    }
    return 0;
}

# 动态规划

# 斐波那契

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
    int F[45],n;
    F[0] = F[1] = 1;
    for (int i = 2; i <= 44; i++)
        F[i] = F[i - 1] + F[i - 2];
    scanf("%d", &n);
    printf("%d\n", F[n]);
    return 0;
}

# 最长公共子序列

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxx = 1010;
int c[maxx][maxx];
int lcs(char s1[],char s2[]) {
    int m = strlen(s1), n = strlen(s2);
    for (int i = 1; i <= m; i++)
        c[i][0] = 0;
    for (int i = 1; i <= n; i++)
        c[0][i] = 0;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (s1[i] == s2[j])
                c[i+1][j+1] = c[i][j] + 1;
            else
                c[i+1][j+1] = max(c[i][j+1], c[i + 1][j]);
        }
    }
    return c[m][n];
}
int main()
{
    char s1[maxx], s2[maxx];
    int t;
    scanf("%d", &t);
    for (int i = 0; i < t; i++) {
        scanf("%s %s", s1, s2);
        printf("%d\n",lcs(s1,s2));
    }
    return 0;
}

# 矩阵连乘

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxx = 110;
const int INF = 1 << 30;
int main()
{
    int n, p[maxx], m[maxx][maxx];
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d %d", &p[i - 1], &p[i]);
    for (int i = 1; i <= n; i++)
        m[i][i] = 0;
    for (int l = 2; l <= n; l++) {
        for (int i = 1; i <= n - l + 1; i++) {
            int j = i + l - 1;
            m[i][j] = INF;
            for (int k = i; k <= j - 1; k++)
                m[i][j] = min(m[i][j], m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j]);
        }
    }
    printf("%d\n", m[1][n]);
    return 0;
}

#

# 图的表示

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxx = 110;
int main()
{
    int n, m[maxx][maxx];
    int u, num, v;
    scanf("%d", &n);
    memset(m, 0, sizeof(m));
    for (int i = 1; i <= n; i++) {
        scanf("%d %d", &u, &num);
        for (int j = 1; j <= num; j++) {
            scanf("%d", &v);
            m[u][v] = 1;
        }
    }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            printf("%d%c", m[i][j], j == n ? '\n' : ' ');
    return 0;
}

# DFS

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
const int maxx = 110;
int n, m[maxx][maxx];
int u, num, v;
int d[maxx], f[maxx];
int flag[maxx];
int nowtime = 1;
void dfs(int u) {
    // 入栈时间
    flag[u] = 1;
    d[u] = nowtime++;
    for (int i = 1; i <= n; i++) {
        if (flag[i] == 0 && m[u][i] == 1) {
            dfs(i);
        }
    }
    // 出栈时间
    f[u] = nowtime++;
}
int main()
{
    scanf("%d", &n);
    memset(m, 0, sizeof(m));
    memset(f, 0, sizeof(f));
    for (int i = 1; i <= n; i++) {
        scanf("%d %d", &u, &num);
        for (int j = 1; j <= num; j++) {
            scanf("%d", &v);
            m[u][v] = 1;
        }
    }
    for (int i = 1; i <= n; i++) {
        if(flag[i] == 0)
            dfs(i);
    }
    for (int i = 1; i <= n; i++) {
        printf("%d %d %d\n", i, d[i], f[i]);
    }
    return 0;
}

# BFS

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxx = 110;
int n, m[maxx][maxx];
int u, num, v;
int flag[maxx];
int d[maxx];
void bfs() {
    queue<int>q;
    q.push(1);
    d[1] = 0;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = 2; i <= n; i++) {
            if (m[u][i] == 1 && flag[i] == 0) {
                // 标记为已经访问
                flag[i] = 1;
                // 更新长度
                d[i] = d[u] + 1;
                // 压入栈内
                q.push(i);
            }
        }
    }
}
int main()
{
    scanf("%d", &n);
    memset(m, 0, sizeof(m));
    for (int i = 1; i <= n; i++) {
        scanf("%d %d", &u, &num);
        // 初始化
        flag[i] = 0;
        d[i] = -1;
        for (int j = 1; j <= num; j++) {
            scanf("%d", &v);
            m[u][v] = 1;
        }
    }
    bfs();
    for (int i = 1; i <= n; i++) {
        printf("%d %d\n", i, d[i]);
    }
    return 0;
}

# 连通分量

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
using namespace std;
const int maxx = 100010;
int n, m;
int u, num, v;
int flag[maxx];
int color[maxx];
vector<int> G[maxx];
int c = 1;
void dfs(int t) {
    stack<int>s;
    s.push(t);
    color[t] = c;
    while (!s.empty()) {
        int u = s.top(); s.pop();
        int len = G[u].size();
        for (int i = 0; i < len; i++) {
            int v = G[u][i];
            if (flag[v] == 0) {
                color[v] = c;
                flag[v] = 1;
                s.push(v);
            }
        }
    }
}
int main()
{
    int q;
    memset(flag, 0, sizeof(flag));
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; i++) {
        scanf("%d %d", &u, &v);
        // 将顶点 v 添加到 G [u] 数组中
        G[u].push_back(v);
        G[v].push_back(u);
    }
    for (int i = 0; i < n; i++) {
        if (flag[i] == 0) {
            dfs(i);
            c++;
        }
    }
    scanf("%d", &q);
    for (int i = 0; i < q; i++) {
        scanf("%d %d", &u, &v);
        if (color[u] == color[v]) {
            printf("yes\n");
        }
        else {
            printf("no\n");
        }
    }
    return 0;
}