天天看點

一維數組模拟單連結清單、鄰接表和雙連結清單--模闆

單連結清單 —— 模闆題 AcWing 826. 單連結清單

實作一個單連結清單,連結清單初始為空,支援三種操作:

(1) 向連結清單頭插入一個數;
(2) 删除第k個插入的數後面的數;
(3) 在第k個插入的數後插入一個數

現在要對該連結清單進行M次操作,進行完所有操作後,從頭到尾輸出整個連結清單。

注意:題目中第k個插入的數并不是指目前連結清單的第k個數。例如操作過程中一共插入了n個數,則按照插入的時間順序,這n個數依次為:第1個插入的數,第2個插入的數,…第n個插入的數。

輸入格式
第一行包含整數M,表示操作次數。
接下來M行,每行包含一個操作指令,操作指令可能為以下幾種:

(1) “H x”,表示向連結清單頭插入一個數x。
(2) “D k”,表示删除第k個輸入的數後面的數(當k為0時,表示删除頭結點)。
(3) “I k x”,表示在第k個輸入的數後面插入一個數x(此操作中k均大于0)。

輸出格式
共一行,将整個連結清單從頭到尾輸出。

資料範圍
1≤M≤100000
所有操作保證合法。

輸入樣例:
10
H 9
I 1 1
D 1
D 0
H 6
I 3 6
I 4 5
I 4 5
I 3 4
D 6
輸出樣例:
6 4 6 5


#include<bits/stdc++.h>
#define N 100000+10
using namespace std;
int head=-1,e[N],ne[N],idx=0;

void add_head(int x){
    e[idx]=x;
    ne[idx]=head;
    head=idx++;
}

void insert(int k,int x){
    e[idx]=x;
    ne[idx]=ne[k];
    ne[k]=idx++;
}

void del(int k){
    ne[k]=ne[ne[k]];
}

int main(){
    int m;
    cin>>m;
    while(m--){
        char c;
        scanf(" %c",&c);
        if (c=='H'){
            int t;
            scanf("%d",&t);
            add_head(t);
        }
        if (c=='D'){
            int t;
            scanf("%d",&t);
            if (t==0) head=ne[head];
            else del(t-1);
        }
        
        if (c=='I'){
            int k,x;
            scanf("%d%d",&k,&x);
            insert(k-1,x);
        }
    }
    
    for (int i=head;i!=-1;i=ne[i])
        cout<<e[i]<<' ';
    
    return 0;
}
           

單連結清單說明

// head存儲連結清單頭
//e[]存儲節點的值
//ne[]存儲節點的next指針
//idx表示目前用到了哪個節點
int head, e[N], ne[N], idx;

// 初始化
void init()
{
    head = -1;
    idx = 0;
}

// 在連結清單頭插入一個數x
void insert(int x)
{
    e[idx] = x;
    ne[idx] = head;
    head = idx;
    idx++;
}

//把x插入到下标是k的點後面
void add(int k,int x){
   e[idx]=x;
   ne[idx]=ne[k];
   ne[k]=idx;
   idx++;   
}

//将下标是k的點的後面一個點删除
void del(int k){
   ne[k]=ne[ne[k]];
}

// 将頭結點删除,需要保證頭結點存在
void del_herad()
{
    head = ne[head];
}
           

鄰接表(多個單連結清單,用來在存儲圖和樹)

方法1:

結構體模拟鄰接表:為每個點開個單連結清單,分别存儲該點的所有鄰邊

void insert(int u, int v) { 
    e[idx].v = v; 
    e[idx].next = p[u]; 
    p[u] = idx++;
}
代碼解釋
u所連的邊構成了一條連結清單,p[u]是頭節點,表示的是邊的标号

e[i].v表示第 i 條邊所到達的點,

e[i].next是連結清單中的下一個節點,表示的也是邊的标号
           

方法2:(推薦)

 int h[N], e[M], v[M], ne[M], idx;   // 數組模拟鄰接表

#include <bits/stdc++.h>
using namespace std;
const int N = 100010, M = 2000010;

int n, m;
int price[N];
int h[N], rh[N], e[M], ne[M], idx;
int dmin[N], dmax[N];
bool st[N];

void add(int a, int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx ++ ;
}

void spfa(int *d, int start, int *h, bool flag)
{
    queue<int> q;
    memset(st, 0, sizeof st);

    if (flag) memset(d, 0x3f, sizeof dmin);

    q.push(start);
    st[start] = true;
    d[start] = price[start];

    while (q.size())
    {
        int t = q.front();
        q.pop();
        st[t] = false;

        for (int i = h[t]; ~i; i = ne[i])
        {
            int j = e[i];
            if (flag && d[j] > min(d[t], price[j]) || !flag && d[j] < max(d[t], price[j]))
            {
                if (flag) d[j] = min(d[t], price[j]);
                else d[j] = max(d[t], price[j]);

                if (!st[j])
                {
                    st[j] = true;
                    q.push(j);
                }
            }
        }
    }
}

int main()
{
    scanf("%d%d", &n, &m);

    memset(h, -1, sizeof h);
    memset(rh, -1, sizeof rh);

    for (int i = 1; i <= n; i ++ ) scanf("%d", &price[i]);
    while (m -- )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(h, a, b), add(rh, b, a);
        if (c == 2) add(h, b, a), add(rh, a, b);
    }

    spfa(dmin, 1, h, true);
    spfa(dmax, n, rh, false);

    int res = 0;
    for (int i = 1; i <= n; i ++ ) res = max(res, dmax[i] - dmin[i]);

    printf("%d\n", res);

    return 0;
}
           

雙連結清單 —— 模闆題 AcWing 827. 雙連結清單

// e[]表示節點的值,l[]表示節點的左指針,r[]表示節點的右指針,idx表示目前用到了哪個節點
int e[N], l[N], r[N], idx;

// 初始化
void init()
{
    //0是左端點,1是右端點
    r[0] = 1, l[1] = 0;
    idx = 2;
}

// 在節點a的右邊插入一個數x
void insert(int k, int x)
{
    e[idx] = x;
    l[idx] = k, r[idx] = r[k];
    l[r[k]] = idx, r[k] = idx ++ ;
}

// 删除節點k
void remove(int k)
{
    l[r[k]] = l[k];
    r[l[k]] = r[k];
}