• HXD的DS


    1.线性表的增删改查

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct node
    {
    	int element;//数据域
    	struct node * link;//指针域
    }Node;
    
    typedef struct headerList
    {
    	Node * head;
    	int n;
    }HeaderList;
    
    int Init(HeaderList * h);//单链表初始化
    int Find(HeaderList h, int i, int *x);//单链表的查找
    int Insert(HeaderList * h, int i, int x);//单链表的插入
    int Delete(HeaderList * h, int i);//单链表的删除
    int Output(HeaderList * h);//单链表的输出
    void Change(HeaderList * h, int i, int x);//修改元素
    void Destroy(HeaderList * h);//单链表的撤销
    
    HeaderList list;
    
    int main()
    {
    	Init(&list);//初始化
    	for (int i = 0; i < 9; i++) Insert(&list, i - 1, i);
    
    	printf("THE LIST IS:
    ");
    	Output(&list);
    
    	Delete(&list, 0);
    	printf("
    AFTER DELETE THE LIST IS:
    ");
    	Output(&list);
    
    	Change(&list, 3, 22);
    	printf("
    AFTER CHANGE
    ");
    	Output(&list);
    
    	int temp;
    	Find(list, 0, &temp);
    	printf("
    FIND VALUE: %d
    ", temp);
    
    	Destroy(&list);
    
    	system("pause");
    	return 0;
    }
    
    int Init(HeaderList * h)
    {
    	h->head = (Node *)malloc(sizeof(Node));
    
    	if (!h->head) return 0;
    
    	h->head->link = NULL;
    	h->n = 0;
    
    	return 1;
    }
    
    int Find(HeaderList h, int i, int *x)
    {
    	Node *p;
    
    	if (i < 0 || i > h.n - 1) return 0;//判断下标越界
    
    	p = h.head;//c从头节点查找
    	for (int j = 0; j <= i; j++) p = p->link;
    
    	*x = p->element;
    	return 1;
    }
    
    int Insert(HeaderList * h, int i, int x)
    {
    	Node *p, *q;
    
    	if (i < -1 || i > h->n - 1) return 0;//判断越界
    
    	p = h->head;
    	for (int j = 0; j <= i; j++) p = p->link;
    
    	q = (Node *)malloc(sizeof(Node));
    	q->element = x;
    	q->link = p->link;
    	p->link = q;
    	h->n++;
    
    	return 1;
    }
    
    int Delete(HeaderList * h, int i)
    {
    	Node *p, *q;
    
    	if (!h->n) return 0;//判断是否为空
    	if (i < 0 || i > h->n - 1) return 0;//判断越界
    
    	q = h->head;
    	for (int j = 0; j < i; j++) q = q->link;
    	p = q->link;
    	q->link = p->link;
    	free(p);
    	h->n--;
    
    	return 1;
    }
    
    int Output(HeaderList * h)
    {
    	Node *p;
    
    	if (!h->n) return 0;//判断是否为空
    
    	p = h->head->link;
    
    	while (p)
    	{
    		printf("%d ", p->element);
    		p = p->link;
    	}
    
    	return 1;
    }
    
    void Destroy(HeaderList * h)
    {
    	Node *p;
    	while (h->head)
    	{
    		p = h->head->link;
    		free(h->head);
    		h->head = p;
    	}
    }
    
    void Change(HeaderList * h, int i, int x)
    {
    	Node *p;
    
    	if (i < 0 || i > h->n - 1) return;//判断下标越界
    
    	p = h->head;//c从头节点查找
    	for (int j = 0; j <= i; j++) p = p->link;
    
    	p->element = x;
    }
    

    2.两个有序单向链表的归并(数组模拟的静态链表实现)

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    const int N = 10010;
    
    int h[3], e[N], ne[N], idx;//h数组为头指针,h[0], h[1]为两个有序链表,归并后的链表是h[2]
    
    void add(int a, int b)
    {
        e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
    }
    
    int main()
    {
        memset(h, -1, sizeof h);//初始化头指针
        
        //构造两条降序链表
        for (int i = 0; i < 10; i ++ )
        {
            add(0, i);
            add(1, i * i);
        }
        
        puts("");
        
        int i = h[0], j = h[1];
        for ( ; ~i && ~j; )
        {
            int a = e[i], b = e[j];
            
            if (e[i] >= e[j])
            {
                add(2, e[i]);
                i = ne[i];//指向下一个结点
            }
            else
            {
                add(2, e[j]);
                j = ne[j];//指向下一个结点
            }
        }
        
        //扫尾
        while (~i) add(2, e[i]), i = ne[i];
        while (~j) add(2, e[j]), j = ne[j];
        
        for (int i = h[2]; ~i; i = ne[i])
            cout << e[i] << ' ';
        
        puts("");
        
        return 0;
    }
    

    3.栈与队列

    #include <iostream>
    
    using namespace std;
    
    const int N = 1010;
    
    int q[N];
    int cnt = 20;//假设有20张票
    
    int main()
    {
        int hh = 0, tt = -1;
        int i = 1;//队列中人的序号
        
        for (int j = 1; j <= 3; j ++ )
            q[ ++ tt] = i ++ ;//假设初始队伍中有3个人
        
        cnt -= 3;
        
        while (hh <= tt)
        {
            auto t = q[hh ++ ];//队头买完票出队
            
            cnt -- ;//票余量减一
            if (cnt >= 0)//如果还有余票
                q[ ++ tt] = i ++ ;
                
            cout << t << ' ';//输出队伍
        }
        
        return 0;
    }
    

    4.二叉树的遍历(先,中,后,BFS层次遍历)

    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <queue>
    
    using namespace std;
    
    typedef struct btnode
    {
    	char element;
    	struct btnode * lc, *rc;
    }BTNode;
    
    BTNode * PreCreateBT(BTNode * t);//先序遍历构建二叉树
    void PreOrderTraversal(BTNode * t);//先序遍历二叉树,DFS递归做法
    void InOrderTraversal(BTNode * t);//中序遍历二叉树
    void PostOrderTraversal(BTNode * t);//后序遍历二叉树
    void BFS(BTNode * t);//层次遍历二叉树,BFS宽搜
    
    int main()
    {
    	BTNode * root = NULL;
    	root = PreCreateBT(root);
    
    	//先序遍历二叉树
    	cout << "PreOrderTraversal BT tree is :" << endl;
    	PreOrderTraversal(root);
    	puts("");
    
    	//中序遍历二叉树
    	cout << "InOrderTraversal BT tree is :" << endl;
    	InOrderTraversal(root);
    	puts("");
    
    	//后序遍历二叉树
    	cout << "PostOrderTraversal BT tree is :" << endl;
    	PostOrderTraversal(root);
    	puts("");
    
    	//宽度优先遍历二叉树
    	cout << "宽度遍历二叉树:" << endl;
    	BFS(root);
    	puts("");
    
    	system("pause");
    	return 0;
    }
    
    BTNode * PreCreateBT(BTNode * t)
    {
    	char ch;
    	ch = getchar();
    
    	if (ch == '#')
    		t = NULL;//空结点
    	else
    	{
    		t = (BTNode *)malloc(sizeof(BTNode));
    		t->element = ch;
    		t->lc = PreCreateBT(t->lc);//构造左儿子
    		t->rc = PreCreateBT(t->rc);//构造右儿子
    	}
    
    	return t;
    }
    
    void PreOrderTraversal(BTNode * t)
    {
    	if (!t)//树空返回
    		return;
    
    	cout << t->element;
    	PreOrderTraversal(t->lc);//递归左儿子
    	PreOrderTraversal(t->rc);//递归右儿子
    }
    
    void InOrderTraversal(BTNode * t)
    {
    	if (!t)//树空返回
    		return;
    
    	InOrderTraversal(t->lc);//递归左儿子
    	cout << t->element;
    	InOrderTraversal(t->rc);//递归右儿子
    }
    
    void PostOrderTraversal(BTNode * t)
    {
    	if (!t)//树空返回
    		return;
    
    	PostOrderTraversal(t->lc);//递归左儿子
    	PostOrderTraversal(t->rc);//递归右儿子
    	cout << t->element;
    }
    
    void BFS(BTNode * t)
    {
    	queue<BTNode *> q;
    	q.push(t);//根结点入队
    
    	while (q.size())
    	{
    		auto t = q.front();//取队头
    		q.pop();//队头出队
    
    		cout << t->element;
    
    		if (t->lc) q.push(t->lc);//如果存在左儿子,入队
    		if (t->rc) q.push(t->rc);//如果存在右儿子,入队
    	}
    }
    
    

    5.哈夫曼树的搭建,编码与解码的实现

    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <string>
    
    using namespace std;
    
    const int N = 30;
    
    struct leaf
    {
    	int value;
    	int parent, lc, rc;//存放父节点,左儿子,右儿子的下标
    };
    
    map<int, char> m1;//权重与字符的映射
    map<int, int> m2;//权重与对应结构体下标的映射
    map<int, int> m3;//权重与对应结构体下标的反映射
    int h[N], idx;//数组模拟的小根堆
    int cnt;//字符的数量
    leaf *root = new leaf[N << 1];//申请哈夫曼树所需的空间,结构体数组
    string s;//存放字符的哈夫曼编码
    
    void down(int u);//小根堆的down操作
    void up(int u);//小根堆的up操作
    void PrintTree(int t);//打印字符和对应的哈夫曼编码
    void CrackCode(string str);//解码
    
    int main()
    {
    	char ch;//字符
    	int rank;//权重
    
    	for (int i = 0; i < 2 * N; i++)
    		root[i].parent = root[i].lc = root[i].rc = -1;
    
    	while (cin >> ch >> rank && ch != '#')
    	{
    		root[cnt].value = rank;//初始化只有根结点的森林
    		m1[rank] = ch;//构造权重与字符的映射
    		m3[cnt] = rank;//构造权重与结构体下标的映射
    		m2[rank] = cnt++;//构造权重与结构体下标的反映射
    		h[++idx] = rank;//权重入堆
    	}
    	for (int i = idx / 2; i; i--) down(i);//O(n)的建堆方式,从倒数第二层开始down下去
    
    	int n = cnt;
    	for (int i = n; i < 2 * n - 1; i++)
    	{
    		int lchild, rchild;
    
    		if (idx >= 2)
    		{
    			lchild = m2[h[1]];//取出权重最小的权重下标作为左儿子
    			h[1] = h[idx--], down(1);//出堆并维持小根堆
    			rchild = m2[h[1]];
    
    			h[1] = h[idx--], down(1);//出堆并维持小根堆
    
    									 //找父结点
    			root[lchild].parent = i;
    			root[rchild].parent = i;
    
    			//找左右儿子
    			root[i].lc = lchild;
    			root[i].rc = rchild;
    
    			//父结点权重为左右儿子权重和
    			root[i].value = root[lchild].value + root[rchild].value;
    
    			//构造父结点和对应结构体数组下标的映射
    			m3[cnt] = root[i].value;
    			m2[root[i].value] = cnt++;
    
    			h[++idx] = root[i].value;//新的结点入堆
    			up(idx);//维持小根堆
    
    		}
    	}
    
    	cout << endl << "字符编码:" << endl;
    	PrintTree(m2[h[1]]);
    
    	string str;
    	cout << endl << "Input a string :(二进制字符串)" << endl;
    	cin >> str;
    
    	CrackCode(str);//解码
    
    	delete[] root;
    
    	system("pause");
    	return 0;
    }
    
    void down(int u)
    {
    	int t = u;
    	if (u * 2 <= idx && h[u * 2] < h[t]) t = u * 2;
    	if (u * 2 + 1 <= idx && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    
    	if (u != t)
    	{
    		swap(h[t], h[u]);
    		down(t);
    	}
    }
    
    void up(int u)
    {
    	while (u / 2 && h[u] < h[u / 2])
    	{
    		swap(h[u / 2], h[u]);
    		u /= 2;
    	}
    }
    
    void PrintTree(int t)
    {
    	if (root[t].lc < 0)//打印叶子结点
    	{
    		cout << m1[root[t].value] << ' ';
    		cout << s << endl;
    		return;
    	}
    	string temp;
    	temp = s;
    
    	s += '0';
    	PrintTree(root[t].lc);
    	s = temp;//恢复到递归前的状态
    	s += '1';
    	PrintTree(root[t].rc);
    	s = temp;//恢复到递归前的状态
    }
    
    void CrackCode(string str)
    {
    	int ini = m2[h[1]];//从根结点开始找
    	for (int i = 0; str[i]; i++)
    	{
    		int t = str[i] - '0';
    
    		if (!t)//t为0,向左儿子移动
    			ini = root[ini].lc;
    		else//否则向右儿子移动
    			ini = root[ini].rc;
    
    		if (root[ini].lc < 0)//到达叶结点
    		{
    			cout << m1[root[ini].value];
    			ini = m2[h[1]];//重新从根结点搜索
    		}
    	}
    }
    
    

    6.Prim求最小生成树

    n个点m条边,接下来m行的三个数a b c表示存在从a到b权值为c的一条边

    求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

    输入样例:

    4 5
    1 2 1
    1 3 2
    1 4 3
    2 3 2
    3 4 4
    

    输出样例:

    6
    
    代码:
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    const int N = 510, INF = 0x3f3f3f3f;
    
    int g[N][N], dist[N];
    bool st[N];
    int n, m;
    
    int prim()
    {
        memset(dist, 0x3f, sizeof dist);
        
        int res = 0;
        
        for (int i = 0; i < n; i ++ )
        {
            int t = -1;
            for (int j = 1; j <= n; j ++ )
                if(!st[j] && (t == -1 || dist[t] > dist[j]))
                    t = j;
            
            if(i && dist[t] == INF) return INF;
            if(i) res += dist[t];
            
            st[t] = true;
            
            for (int j = 1; j <= n; j ++ )
                dist[j] = min(dist[j], g[t][j]);
        }
        
        return res;
    }
    
    int main()
    {
        memset(g, 0x3f, sizeof g);
        
        scanf("%d%d", &n, &m);
        while (m -- )
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            
            g[a][b] = g[b][a] = min(g[a][b], c);
        }
        
        int t = prim();
        
        if(t == INF) puts("impossible");
        else printf("%d
    ", t);
        
        return 0;
    }
    

    7.最短路算法(适用于稠密图的朴素版Dijkstra与堆优化版适用于稀疏图的Dijkstra算法)

    1.适用于稠密图的朴素版Dijkstra算法(O(n²))

    输入样例:

    3 3
    1 2 2
    2 3 1
    1 3 4
    

    输出样例:

    3
    
    代码:
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    
    using namespace std;
    
    const int N = 510;
    
    int g[N][N], dist[N];
    int n, m;
    bool st[N];
    
    int dijkstra()
    {
        memset(dist, 0x3f, sizeof dist);
        dist[1] = 0;
        
        for (int i = 0; i < n - 1; i ++ )
        {
            int t = -1;
            for (int j = 1; j <= n; j ++ )
                if(!st[j] && (t == -1 || dist[t] > dist[j]))
                    t = j;
                
            for (int j = 1; j <= n; j ++ )
                dist[j] = min(dist[j], dist[t] + g[t][j]);
            
            st[t] = true;
        }
        
        if(dist[n] == 0x3f3f3f3f) return -1;
        else return dist[n];
    }
    
    int main()
    {
        memset(g, 0x3f, sizeof g);
        
        cin >> n >> m;
        
        while ( m -- )
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            
            g[a][b] = min(g[a][b], c);
        }
        
        printf("%d
    ", dijkstra());
        
        return 0;
    }
    
    2.堆优化版适用于稀疏图的Dijkstra(O(mlogn))(m边数 ,n点数)

    输入样例:

    3 3
    1 2 2
    2 3 1
    1 3 4
    

    输出样例:

    3
    
    代码:
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    const int N = 1e6 + 10;
    
    int n, m;
    int h[N], w[N], e[N], ne[N], idx;
    int dist[N];
    bool st[N];
    
    void add(int a, int b, int c)
    {
        e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
    }
    
    int dijkstra()
    {
        memset(dist, 0x3f, sizeof dist);
        dist[1] = 0;
        priority_queue<PII, vector<PII>, greater<PII>> heap;
        heap.push({0, 1});
    
        while (heap.size())
        {
            auto t = heap.top();
            heap.pop();
    
            int ver = t.second, distance = t.first;
    
            if (st[ver]) continue;
            st[ver] = true;
    
            for (int i = h[ver]; i != -1; i = ne[i])
            {
                int j = e[i];
                if (dist[j] > dist[ver] + w[i])
                {
                    dist[j] = dist[ver] + w[i];
                    heap.push({dist[j], j});
                }
            }
        }
    
        if (dist[n] == 0x3f3f3f3f) return -1;
        return dist[n];
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
    
        memset(h, -1, sizeof h);
        while (m -- )
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            add(a, b, c);
        }
    
        cout << dijkstra() << endl;
    
        return 0;
    }
    
    

    8.归并排序+快速排序+堆排序

    三个排序的输入一致,第一行为n表示数字个数,第二行输入n个数字

    (1).归并排序
    #include <iostream>
    
    using namespace std;
    
    const int N = 1e6 + 10;
    
    int q[N], temp[N], n;
    
    void merge_sort(int q[], int l, int r)
    {
        if(l >= r) return;
        
        int mid = l + r >> 1;
        
        merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
        
        int k = 0, i = l, j = mid + 1;
        
        while (i <= mid && j <= r)
            if(q[i] <= q[j]) temp[k ++ ] = q[i ++ ];
            else temp[k ++ ] = q[j ++ ];
        
        while (i <= mid) temp[k ++ ] = q[i ++ ];
        while (j <= r) temp[k ++ ] = q[j ++ ];
        
        for (int i = l, j = 0; i <= r; i ++ , j ++ ) q[i] = temp[j];
    }
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 0; i < n; i ++ ) scanf("%d", q + i);
        
        merge_sort(q, 0, n - 1);
        
        for (int i = 0; i < n; i ++ ) printf("%d ", q[i]);
        
        return 0;
    }
    
    (2).快速排序
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 1e6 + 10;
    
    int q[N], n;
    
    void quick_sort(int q[], int l, int r)
    {
        if(l >= r) return;
        
        int x = q[l + r >> 1], i = l - 1, j = r + 1;
        while(i < j)
        {
            do i ++ ; while(q[i] < x);
            do j -- ; while(q[j] > x);
            
            if(i < j) swap(q[i], q[j]);
        }
        
        quick_sort(q, l, j), quick_sort(q, j + 1, r);
    }
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 0; i < n; i ++ ) scanf("%d", q + i);
        
        quick_sort(q, 0, n - 1);
        
        for (int i = 0; i < n; i ++ ) printf("%d ", q[i]);
        
        return 0;
    }
    
    (3).堆排序
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 1e5 + 10;
    
    int h[N], idx;
    int n;
    
    
    void down(int u)
    {
        int t = u;
        if(u * 2 <= idx && h[u * 2] < h[t]) t = u * 2;
        if(u * 2 + 1 <= idx && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
        
        if(u != t)
        {
            swap(h[t], h[u]);
            down(t);
        }
    }
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i ++ ) scanf("%d", h + i);
        idx = n;
        
        for (int i = n / 2; i; i -- ) down(i);
        
        while (n -- )
        {
            printf("%d ", h[1]);
            h[1] = h[idx -- ];
            down(1);
        }
        puts("");
        
        return 0;
    }
    
  • 相关阅读:
    关于匹配的一些问题
    Codeforces Round #396 (Div. 2) A,B,C,D,E
    Codeforces Round #394 (Div. 2) A,B,C,D,E
    HDU 1848 SG函数博弈
    HDU 1536 S-Nim SG博弈
    HDU 2509 Be the Winner nim博弈变形
    HDU 1907 John nim博弈变形
    Codeforces Round #222 (Div. 1) D. Developing Game 线段树有效区间合并
    BZOJ 1031: [JSOI2007]字符加密Cipher 后缀数组
    HDU 5769 Substring 后缀数组
  • 原文地址:https://www.cnblogs.com/scl0725/p/13939973.html
Copyright © 2020-2023  润新知