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

posted @ 2016-12-29 12:21  Wasdns  阅读(324)  评论(0编辑  收藏  举报