Open Data Structure Templates

数据结构模板 Chen 2016/12/22

Open Source in Github: https://github.com/Wasdns/DataStructure-Templates

前言

本篇博客的模板,全部是我纯手打的,如果有发现错误,请在下方留言指正:)。欢迎大家参考。

有一些地方还不是很完善,等过一阵子用C++实现和部分重构下。

C/C++ 常用字符串函数

#include <string.h>

strcpy

char * strcpy( char * dest, const char * src );

功能:把 src 所指由NULL结束的字符串复制到 dest 所指的数组中。

说明:src 和 dest 所指内存区域不可以重叠且 dest 必须有足够的空间来容纳 src 的字符串。返回指向 dest 结尾处字符(NULL)的指针。

strcmp

int strcmp ( const char * str1, const char * str2 );

功能:比较字符串 str1 和 str2。

说明:

当s1<s2时,返回值<0

当s1=s2时,返回值=0

当s1>s2时,返回值>0

strlen

size_t strlen ( const char * str );

功能:计算字符串 str 的长度

说明:返回 str 的长度,不包括结束符NULL。(注意与 sizeof 的区别)

C++:StringStream

#include <sstream>

int a;

stringstream ss;
ss << "32";
ss >> a;
ss.clear();

排序

相关定义

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; /*存储数组定义*/ int num[100005]; void swap1(int i, int j)
{
int t = num[i];
num[i] = num[j];
num[j] = t;
} /*Printnum 输出*/ void Printnum(int n)
{
for (int i = 1; i <= n; i++) {
cout << num[i] << " ";
} cout << endl;
}

冒泡排序

/*Bubble_Sort 冒泡排序*/

void Bubble_Sort(int n)
{
int i, j; for (i = 1; i <= n; i++) //遍历n次
{
for (j = 1; j <= n-i; j++) //每次都把最大数往后排,缩小范围
{
if (num[j] > num[j+1])
{
swap1(j, j+1);
}
}
}
} void Bubble_Sort_Better(int n)
{
int i, j; for (i = 1; i <= n; i++)
{
bool flag = true; for (j = 1; j <= n-i; j++)
{
if (num[j] > num[j+1])
{
flag = false; swap1(j, j+1);
}
} if (flag) break; //某一次遍历没有发生交换时,结束
}
}

选择排序

/*Selection_Sort 选择排序*/

void Selection_Sort(int n)
{
int i, j; int rcd; for (i = 1; i <= n; i++)
{
rcd = i; for (j = i+1; j <= n; j++)
{
if (num[j] < num[rcd]) //找出i+1=>n范围内的最小元并前移
{
rcd = j;
}
} swap1(i, rcd);
}
}

归并排序

/*Merge_Sort 归并排序*/

int temp[100005];

void Merge_Array(int l1, int r1, int l2, int r2)
{
int p1 = l1;
int p2 = l2; int i = 1; memset(temp, 0, sizeof(temp)); for (i = l1; i <= r2; i++)
{
if (p1 > r1)
{
temp[i] = num[p2++]; continue;
} if (p2 > r2)
{
temp[i] = num[p1++]; continue;
} if (num[p1] < num[p2])
{
temp[i] = num[p1++]; continue;
} else
{
temp[i] = num[p2++]; continue;
}
} for (i = l1; i <= r2; i++)
{
num[i] = temp[i];
} } void Merge_Sort(int l, int r)
{
if (l < r)
{
int mid = (l+r)/2; Merge_Sort(l, mid); //l => mid
Merge_Sort(mid+1, r); //mid+1 => r Merge_Array(l, mid, mid+1, r); //l => mid => mid+1 => r
}
}

快速排序

/*Quick_Sort 快速排序*/

int Quick_Sort_Adjust(int l, int r)
{
int key = l; //选取第一个元素为基准值 int a, b; a = l+1; b = r; while (a < b)
{
bool out_bound = false; while (1)
{
if (num[a] > num[key]) break; a++; if (a > r)
{
out_bound = true; break;
}
} while (1)
{
if (num[b] < num[key]) break; b--; if (b < l)
{
out_bound = true; break;
}
} if (out_bound || a >= b) break; //如果出现越界或a>=b直接结束 swap1(a, b); a++;
b--;
} swap1(key, a-1); return a-1;
} void Quick_Sort(int l, int r)
{
if (l < r)
{
int mid = Quick_Sort_Adjust(l, r); Quick_Sort(l, mid-1); //l => mid-1
Quick_Sort(mid+1, r); //mid+1 => r
}
}

并查集

并查集

int fa[100005];

void IniFUS(int n)
{
int i; for (i = 1; i <= n; i++)
{
fa[i] = i;
}
} int Find(int x)
{
int f = x; while (f != fa[f])
{
f = fa[f];
} int i = x, j; while (i != f)
{
j = fa[i]; fa[i] = f; i = j;
} return f;
} void Union(int x, int y)
{
int xfa = Find(x);
int yfa = Find(y); if (xfa != yfa) {
fa[yfa] = xfa;
}
}

邻接表

struct edge
{
edge *next;
int num;
int len;
}; edge eg[100000]; struct head
{
edge *next;
int num;
}; head h[100000]; void IniList(int n)
{
int i; for (i = 1; i <= n; i++)
{
h[i].next = NULL;
h[i].num = i;
}
} void CreatList(int x, int y, int leng)
{
edge *p1, *p2; p1 = new edge;
p1 -> next = NULL;
p1 -> num = y;
p1 -> len = leng; p2 = h[x].next; if (p2 == NULL) {
h[x].next = p1;
} else
{
while (p2 -> next != NULL) {
p2 = p2 -> next;
} p2 -> next = p1;
}
}

Dijkstra 单点到多点距离(邻接表实现):

/*
Dijkstra:
1.DijInitial
2.x_HasPath_y
3.Dijkstra
*/ int pre[100005]; //最短路节点的前继节点(查询最短路) int dist[100005]; //源点到每个节点的最短路距离 bool ins[100005]; //节点i是否位于已查询节点集合S void DijInitail(int start, int n)
{
int i; for (i = 1; i <= n; i++)
{
dist[i] = maxn; pre[i] = i; ins[i] = false;
} dist[start] = 0; edge *p; p = h[start].next; while (p != NULL)
{
dist[p->num] = p->len; p = p -> next;
}
} int x_HasPath_y(int x, int y)
{
edge *p; p = h[x].next; while (p != NULL)
{
if (p -> num == y)
{
return p -> len;
} p = p -> next;
} return -1;
} int Dijkstra(int start, int find, int n)
{
int i, j; DijInitail(start, n); ins[start] = true; for (i = 1; i < n; i++) //n-1次
{
int addnum = start; //记录此时V中最靠近源点的节点 int minlen = 1000000; //以及源点到该节点的长度 for (j = 1; j <= n; j++) //源点从V中挑一个最近节点
{
if (ins[j]) continue; //这个节点在S中,跳过 if (dist[j] < minlen) //当前到源点距离最小的节点
{
addnum = j; minlen = dist[j]; //更新离源点最近节点的信息
}
} ins[addnum] = true; for (j = 1; j <= n; j++) //新来的节点向外得到路径信息
{ //并维护dist
if (ins[j]) continue; /* 从源点到当前节点next的距离 + 当前节点next到某个相邻节点j的距离。*/
/* 如果小于目前源点到节点j的最短距离dist[j],更新dist[j]。 */ int pathlen = x_HasPath_y(addnum, j); if (pathlen == -1) continue; int t = dist[addnum] + pathlen; if (t < dist[j])
{
dist[j] = t; pre[j] = addnum;
}
} } return dist[find];
}

Dijkstra 多点到多点(邻接矩阵实现):

int DijGraph[105][105];               //节点i和j之间的距离:DijGraph[i][j]

int pre[105];                         //最短路节点的前继节点(查询最短路)

int dist[105];                        //源点到每个节点的最短路距离

bool ins[105];                        //节点i是否位于已查询节点集合S

/*
初始化函数
*/ void Initial(int n)
{
for (int i = 1; i <= n; i++)
{
ins[i] = false; pre[i] = -1; for (int j = 1; j <= n; j++)
{
if (i == j) DijGraph[i][j] = 0; else DijGraph[i][j] = 1000000;
}
}
} void Dijkstra(int n, int b, int e)
{
int i, j; for (i = 1; i <= n; i++) {
dist[i] = DijGraph[b][i];
} dist[b] = 0;
ins[b] = true; for (i = 2; i <= n; i++)
{
int next = b;
int minlen = 1000000; for (j = 1; j <= n; j++)
{
if (ins[j]) continue; if (dist[j] < minlen) { next = j; minlen = dist[j];
}
} ins[next] = true; for (j = 1; j <= n; j++)
{
if (ins[j]) continue; int t = dist[next] + DijGraph[next][j]; if (t < dist[j])
{
dist[j] = t; pre[j] = next;
}
}
}
}

Prim

int Primgh[10000][10000];                        //存储图

bool refer[10005];                               //判断是否在Enew中

/*
用于初始化的函数
*/ void Initial(int n, int m)
{
int i, j; for (i = 1; i <= n; i++)
{
refer[i] = false; for (j = 1; j <= n; j++)
{
if (i == j) {
Primgh[i][j] = 0;
} else Primgh[i][j] = maxn;
}
} int u, v, w; for (i = 1; i <= m; i++)
{
cin >> u >> v >> w; Primgh[u][v] = w;
Primgh[v][u] = w;
}
} /*
Prim算法,主体部分
*/ int Prim_Alg(int n, int m)
{
Initial(n, m); int i, j, k; int ans = 0;
//最小生成树的路径长度 refer[1] = true;
//选择点1出发 //最小生成树一共有n-1条边,因此需要寻找最短边n-1次,基于贪心
for (i = 1; i <= n-1; i++)
{
int minlen = maxn;
//minlen: 在Vnew中的节点所连接的边中,寻找cost最小的边 int rcd = 1;
//cost最小的边有两个节点,rcd记录其中的不属于Vnew的节点 for (j = 1; j <= n; j++)
{
if (!refer[j]) continue;
//遍历Vnew中的所有节点 int len1 = maxn;
//对于Vnew中的某个节点来说,所连接的最短的路径cost大小 int rcd1 = 1;
//对于Vnew中的某个节点来说,rcd记录的节点 //贪心,寻找这个节点连接的cost最小的路径
for (k = 1; k <= n; k++)
{
if (!refer[k])
{
if (Primgh[j][k] < len1) { len1 = Primgh[j][k]; rcd1 = k;
}
}
} if (len1 < minlen) {
//判断贪心得到的路径是否是全局cost最短 minlen = len1; rcd = rcd1;
}
} /*Debug:*/
//char check = 'A'+rcd-1;
//cout << "rcd: " << check << endl;
//cout << "minlen: " << minlen << endl; refer[rcd] = true;
//贪心求出cost最小的路径,rcd记录的节点入Vnew
rcd = 1;
//重置rcd ans += minlen;
} return ans;
}

Kruskal

struct stedge
{
int u, v, len;
}; bool cmp(stedge s1, stedge s2)
{
return s1.len < s2.len;
} stedge seg[100000]; int fa[100005]; void Inifa(int n)
{
for (int i = 1; i <= n; i++)
{
fa[i] = i;
}
} int findfa(int x)
{
int f = x; while (f != fa[f])
{
f = fa[f];
} int i = x, j; while (i != f)
{
j = fa[i]; fa[i] = f; i = j;
} return f;
} int main()
{
int i, n, m; cin >> n >> m; Inifa(n); int u, v, w; for (i = 1; i <= m; i++)
{
cin >> u >> v >> w; seg[i].u = u;
seg[i].v = v;
seg[i].len = w;
} sort(seg+1, seg+m+1, cmp); int cnt = 0, lencnt = 0; for (i = 1; i <= m; i++)
{
int fa1 = findfa(seg[i].u);
int fa2 = findfa(seg[i].v); if (fa1 == fa2) continue; cnt++; lencnt += seg[i].len; fa[fa1] = fa2; //一定是祖先找祖先合并 if (cnt == n-1) break;
} cout << lencnt; return 0;
}

树的序遍历

//
// main.cpp
// Tree2
//
// Created by wasdns on 16/12/19.
// Copyright © 2016年 wasdns. All rights reserved.
// #include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; struct Node
{
int num; Node *l, *r;
}; int preorder[100005]; int midorder[100005]; int aftorder[100005]; Node *node[100005]; int n; int tot = 1; //记录aftorder /*
Ininode函数:用于初始化节点
*/
void Ininode()
{
int i; for (i = 1; i <= n; i++)
{
Node *p = new Node; p -> num = i;
p -> l = NULL;
p -> r = NULL; node[i] = p;
}
} /*
FindRoot函数:根据后序、中序建树
*/
Node* FindRoot(int aft_l, int aft_r, int mid_l, int mid_r)
{
if (aft_r - aft_l < 0) return NULL; Node *root = new Node; root -> num = aftorder[aft_r]; if (aft_l == aft_r)
{
root -> l = NULL;
root -> r = NULL; return root;
} int index; for (index = mid_l; index <= mid_r; index++)
{
if (midorder[index] == aftorder[aft_r]) break;
} root -> r = FindRoot(aft_r-(mid_r-index), aft_r-1, index+1, mid_r);
root -> l = FindRoot(aft_l, aft_r-(mid_r-index)-1, mid_l, index-1); return root;
} /*
FindRoot函数:根据先序和中序建树。
*/
Node* FindRoot1(int pre_l, int pre_r, int mid_l, int mid_r)
{
if (pre_r - pre_l < 0) return NULL; Node* root = new Node; /*将先序列表中最左边的节点作为root*/
root -> num = preorder[pre_l]; if (pre_l == pre_r)
{
root -> l = NULL;
root -> r = NULL; return root;
} /*在中序中找到root所在的位置,用index表示*/
int index; for (index = mid_l; index <= mid_r; index++)
{
if (midorder[index] == preorder[pre_l]) break;
} /*说明:利用index进行递归,分成左子树和右子树。 */
/*同时将先序序列和后序序列进行划分,将位置作为递归的参数。*/
root -> l = FindRoot1(pre_l+1, pre_l+(index-mid_l), mid_l, index-1);
root -> r = FindRoot1(pre_l+(index-mid_l)+1, pre_r, index+1, mid_r); return root;
} /*
CalAftorder函数:根据给定的树来计算后序序列
*/
void CalAftorder(Node *head)
{
if (head == NULL) return ; CalAftorder(head -> l);
CalAftorder(head -> r); aftorder[tot++] = head -> num;
} /*
CalPreorder函数:根据给定的树来计算先序序列
*/
void CalPreorder(Node *head)
{
if (head == NULL) return ; preorder[tot++] = head -> num; CalPreorder(head -> l);
CalPreorder(head -> r);
} /*
Print函数:输出先序、后序序列
*/
void Print()
{
int i; for (i = 1; i <= n; i++) {
cout << preorder[i] << " ";
} cout << endl; for (i = 1; i <= n; i++) {
cout << aftorder[i] << " ";
} cout << endl;
}

优先队列 STL

值大 => 优先级高

#include <iostream>
#include <queue>
using namespace std; priority_queue<int> q;

值小 => 优先级高

#include <iostream>
#include <functional>
#include <queue>
using namespace std; struct cmp
{
bool operator() (int x,int y) {
return x > y;
}
}; priority_queue<int, vector<int>, cmp> q;

结构体:

struct node
{
int x, y;
friend bool operator < (node a, node b)
{
return a.x > b.x; //结构体中,x小的优先级高
}
};
priority_queue<node>q;//定义方法
//在该结构中,y为值, x为优先级。
//通过自定义operator<操作符来比较元素中的优先级。
//在重载”<”时,最好不要重载”>”,可能会发生编译错误

手写Heap堆:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; int size = 0; int Heap[100005]; /*
维护函数keep
*/
void keep(int son)
{
int fa = son/2; while (fa >= 1 && Heap[fa] > Heap[son])
{
int t = Heap[fa];
Heap[fa] = Heap[son];
Heap[son] = t; son = fa;
fa = fa/2;
}
} /*
初始化函数IniHeap
*/
void IniHeap()
{
int i; for (i = size; i >= 1; i--)
{
keep(i);
}
} /*
InsProtect函数:插入新节点并维护
*/
void InsProtect(int a)
{
Heap[++size] = a; keep(size);
} /*
DelMin函数:删除最小元并维护
*/
int DelMin()
{
int minum = Heap[1]; int t = Heap[size]; Heap[1] = t; size--; IniHeap(); return minum;
}

Hash函数

Index哈希函数例1:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn =1000005;
int num[maxn];
char a[maxn],str[10]; int IndexHash(char *key)
{
int hashval = 0;
while (*key != '\0') hashval = (hashval<<5) + *key++;
return hashval;
} int main()
{
//freopen("data.txt","r",stdin);
//freopen("2.txt","w",stdout);
int n,m,k,i,p = 0;
memset(str,0,sizeof(str));
scanf("%d%d%d",&n,&m,&k);
scanf("%s",a);
for (i = 0;i <= n - k;i++)
{
strncpy(str,a + i,k);
int hashval = IndexHash(str);
num[p++] = hashval;
}
sort(num,num+p);
int res = 1;
for (i = 1;i < p;i++)
{
if (num[i] != num[i-1]) res++;
}
printf("%d\n",res);
return 0;
}

例2:

//
// main.cpp
// searchme
//
// Created by wasdns on 16/12/12.
// Copyright © 2016年 wasdns. All rights reserved.
// #include <iostream>
#include <cstdio>
#include <cstring>
#define mod 999983 //int范围内取最大的素数
#define maxn 1000005
using namespace std; /*
Hash函数:IndexHash
*/ int IndexHash(char *s)
{
int hashval = 0; while (*s != '\0') {
hashval = (hashval << 5) + *s++;
} return hashval % mod;
} char searchname[maxn][10]; //你的名字 int head[maxn]; //邻接表的头数组 int lnext[maxn]; //邻接表的节点数组 int tot = 1; //第tot个字符串 /*
AddNode创建邻接表函数:
在head[hashval]中存指向单链表的指针
插入时,现有head的值存入lnext[tot]
之后使head[hashval]成为新的节点
相当于不断在链表的首部进行插入
*/ void AddNode(int hashval)
{
lnext[tot] = head[hashval]; head[hashval] = tot; tot++;
} /*
询问函数:
通过IndexHash得到hash值
利用head[hashval]找到指向对应hash值的单链表
遍历单链表,找到 -> 计数器++。
*/ void query(int q)
{
int cnt = 0; for (int i = 1; i <= q; i++)
{
int hashval = 0; char findname[10]; scanf("%s", findname); hashval = IndexHash(findname); for (int j = head[hashval]; j != -1; j = lnext[j])
{
if (strcmp(searchname[j], findname) == 0) {
cnt++;
}
}
} printf("%d\n", cnt);
} int main()
{
memset(head, -1, sizeof(head));
memset(lnext, -1, sizeof(lnext)); int n, m; cin >> n >> m; int i; for (i = 1; i <= n; i++)
{
scanf("%s", searchname[i]); int hashval = IndexHash(searchname[i]); AddNode(hashval);
} cout << endl; query(m); return 0;
}

2016/12/29

上一篇:vue 动态合并单元格、并添加小计合计功能


下一篇:重大发现Discuz DB层跨库映射关系表名前缀BUG