把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

链表学习笔记

题面传送门
链表,顾名思义,就是一根链,由许多节点构成,每个节点分为两个部分:数据域和指针域,其中数据域可以包含很多数据,指针域只能包含一个指向对象,不然就成图了。链表可以\(O(1)\)插入和删除数据,但不能随机访问元素。
链表实现就不再乱说了。毕竟是个人都会。主要讲一些链表的应用。
这道题很简单,只要顺着链表找下去,找到第m个点就删掉就好了。
代码实现:

#include<cstdio>
using namespace std;
int n,m,f[100039],head,cnt=1,h[100039];
int main(){
    register int i,j;
    scanf("%d%d",&n,&m);
    for(i=2;i<=n;i++) f[i]=i-1;
    f[1]=n;
    for(i=1;i<n;i++) h[i]=i+1;
    h[n]=1;
    for(i=1;i<n;i++){
        for(j=1;j<=m;j++)cnt=h[cnt];
        f[cnt]=f[f[cnt]];
        h[f[cnt]]=cnt;
    }
    printf("%d",cnt);
}

题面传送门
这道题也不难看出是链表,可是如果用单链表的话,我们来模拟一下:
原来是\(1->2->3->4->5\)
第一次插队把\(1\)插到\(2\)的后面。
\(2->1->3->4->5\)
第二次把\(2\)插到\(4\)的后面:
\(1->3->4->2->5\)
第三次把\(3\)插到\(5\)的后面:
\(1->3\)
\(3->2->5->3\)
这就不是链表了,而且也没有我们想要的目的。那么\(3\)怎么找到\(1\)前面的那个呢?那就用双向链表呗!
代码实现:

#include<cstdio>
using namespace std;
int n,m,x,y,f[100039],h[100039],head=1;
int main() {
    register int i;
    scanf("%d%d",&n,&m);
    for(i=2; i<=n; i++) f[i]=i-1;
    for(i=1; i<n; i++) h[i]=i+1;
    for(i=1; i<=m; i++) {
        scanf("%d%d",&x,&y);
        if(!f[x]) {
            head=h[x];
            f[h[x]]=0;
            h[x]=0;
        } else if(!h[x]) {
            h[f[x]]=0;
            f[x]=0;
        } else {
            h[f[x]]=h[x];
            f[h[x]]=f[x];
            f[x]=h[x]=0;
        }
        if(!h[y]) {
            f[x]=y;
            h[y]=x;
        } else {
            f[x]=y;
            h[x]=h[y];
            h[y]=f[h[x]]=x;
        }
        /*int tail=head;
        while(tail) {
            printf("%d ",tail);
            tail=h[tail];
        }
        printf("\n");*/
    }
    while(head) {
        printf("%d ",head);
        head=h[head];
    }
    return 0;
}

注意考虑特殊情况(好像这道题不考虑也没事)
题面传送门
这道题用开放寻址法被卡了,只能用挂链表法。
代码实现:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,ans,h[1000007],head,z[1000007],tot;
string a,f[1000007];
inline void get(string a){
    register int i,tmp,longge=a.size();ans=0;
    for(i=0;i<longge;i++) ans=(ans*259+a[i])%1000039;
    head++;
    f[head]=a;
    z[head]=h[ans];
    h[ans]=head;
     
}
inline int find(string a){
    register int i,tmp,now=0,longge=a.size();ans=0;
    for(i=0;i<longge;i++) ans=(ans*259+a[i])%1000039;
    tmp=h[ans];
    while(tmp>=0){
        if(f[tmp]==a) now++;
        tmp=z[tmp];
    }
    return now;
}
int main(){
    register int i;
    memset(h,-1,sizeof(h));
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        cin>>a;
        if(!find(a)) tot++,get(a);
    }
    printf("%d",tot);
}

题面传送门
这道题要用邻接表来存图。
我们给每一个点做一个链表,只不过这些链表放在一个数组里。每个链表有一个头,我们每次加入都要从头加入。这样遍历时顺着头一路找回去就可以了。
代码实现:

#include<cstdio>
#include<cstring>
using namespace std;
int n,m,x[39],y[39],head,v[39],h[39];
struct yyy{
    int to,z;
}f[39];
inline void add(int x,int y){
    head++;
    f[head].to=y;
    f[head].z=h[x];
    h[x]=head;
}
inline void dfs(int x){
    if(v[x]) return;
    v[x]=1;
    printf("%d ",x);
    for(register int i=h[x];i!=-1;i=f[i].z) dfs(f[i].to);
    return ;
}
int main(){
    memset(h,-1,sizeof(h));
    register int i;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)scanf("%d%d",&x[i],&y[i]);
    for(i=m;i>=1;i--) add(x[i],y[i]),add(y[i],x[i]);
    dfs(1);
    return  0;
}

链表可以应用在很多地方,但是链表只是指针的一个应用,所以我们还是学好指针吧!

posted @ 2020-03-27 09:26  275307894a  阅读(74)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end