紫书第六章-----数据结构基础(数组模拟链表)

数组模拟单链表

例题6-4 Broken Keyboard (a.k.a. Beiju Text) UVA - 11988
这道题目可以直接用STL中list双向链表来做,思路和代码都很简单易想。也可以用数组模拟链表(不易懂)。
之所以不用vector是因为插入删除比较慢慢慢

AC代码(一):
STL的list版本

#include<iostream>
#include<list>
#include<string>
using namespace std;

int main()
{
    string s;
    while(cin>>s){
        list<char>l;
        list<char>::iterator it=l.begin();
        for(int i=0;i<s.length();i++){
            if(s[i]=='[') it=l.begin();
            else if(s[i]==']') it=l.end();
            else{
                it=l.insert(it,s[i]);
                it++;
            }
        }
        for(it=l.begin();it!=l.end();it++)
            cout<<*it;
        cout<<endl;
    }
    return 0;
}

AC代码(二):
数组模拟链表版本

//数组模拟链表
#include<stdio.h>
#include<string.h>

const int maxn=100000+5;
int next[maxn];//next[i]表示链表中第i个结点下一个结点的编号
char s[maxn];
int cur;//当前光标所在位置,即指向当前结点的右侧
int last;//当前最后一个结点的编号

int main()
{
    //s[0]设置为类似链表的头结点,元素从下标1开始编号
    while(scanf("%s",s+1)!=EOF){
        int len=strlen(s+1);
        cur=last=0;
        next[0]=-1;//这里-1仅仅是一个标记,表示起初链表的头结点指向的数值
                    //类似于指针链表初始化时候linklist->next=NULL
        for(int i=1;i<=len;i++){
            if(s[i]=='[') cur=0;//光标定位到开始,指向第0个元素(假想的头结点)的右侧
            else if(s[i]==']') cur=last;//光标定位到最后一个元素,指向最后一个元素的右侧
            else{
            //插入新节点i,类似于链表中创建一个节点i,让他的next指向当前链表头(cur)的next
            //再让当前链表头的next指向节点i
            //和普通链表不同的是这里的链表头cur会变,但是next[0]永远是第一个字符哦
                next[i]=next[cur];
                next[cur]=i;
                if(cur==last) last=i;//如果现在的cur=last,插入新节点后,更新last,手写易明白
                                //由于cur可能会回到头变成0,所以这个操作技巧很好
                cur=i;//插入一个新节点后,cur自然后移,指向当前节点的右侧
            }
        }
        //上述过程完成了建立一个链表的过程,next[0]的值就是第一个字符的下标,next[1]就是第2个节点
        //的下标,以此类推,最后一个节点的next必然是-1,想想链表建立过程,依次往后指,这一点应该很明白
        for(int i=next[0];i!=-1;i=next[i])
            printf("%c",s[i]);
        printf("\n");
    }
    return 0;
}

C语言代码(超时为何?):

#include<stdio.h>
#include<string.h>

const int maxn=100000+5;
char s[maxn];

typedef struct LINK{
    LINK *next;
    LINK *rear;
    LINK *cur;
    char c;
}node,*linklist;

void linklist_init(linklist &lis){
    lis=new node;
    lis->rear=lis;
    lis->next=NULL;
    lis->cur=lis;
}

void linklist_insert(linklist &lis,char e){
    node *p=new node;
    p->next=lis->cur->next;
    p->c=e;
    lis->cur->next=p;
    if(lis->cur==lis->rear) lis->rear=p;
    lis->cur=p;
}

int main()
{
    while(scanf("%s",s)!=EOF){
        linklist lis;
        linklist_init(lis);
        for(int i=0;i<strlen(s);i++){
            if(s[i]=='[') lis->cur=lis;
            else if(s[i]==']'){lis->cur=lis->rear;}
            else{
                linklist_insert(lis,s[i]);
            }
        }
        node *tmp=lis;
        while(tmp->next){
            printf("%c",tmp->next->c);
            tmp=tmp->next;
        }
        printf("\n");
    }
    return 0;
}

数组模拟双向链表

例题6-5 Boxes in a Line UVA - 12657
直接给出参考刘汝佳《算法竞赛入门经典》(第2版)代码参考:

#include<cstdio>

const int maxn=100000+5;
int n,m;
int left[maxn],right[maxn];
int kase=0;

void link(int l,int r){
    right[l]=r;
    left[r]=l;
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=1;i<=n;i++){
            left[i]=i-1;
            right[i]=(i+1)%(n+1);
        }
        left[0]=n;right[0]=1;

        int op,x,y;
        bool inv=0;
        while(m--){
            scanf("%d",&op);
            if(op==4) inv=!inv;
            else{
                scanf("%d%d",&x,&y);
                if(op==3 && right[y]==x){int t=x;x=y;y=t;}//x,y相邻的情形统一变为yx右侧
                //下面这个复合语句坑我了,下面这么写是对的,下面的复合语句全部用if,if是错的
                {
                    if(op==2 && inv) op=1;//逆转后,右边变左边,左边变右边
                    else if(op==1 && inv) op=2;
                }

                if(op==1 && x==left[y]) continue;
                if(op==2 && x==right[y]) continue;

                int lx=left[x],rx=right[x],ly=left[y],ry=right[y];//这样已经保存了x,y的左右值哦,这样很方便后续操作
                if(op==1){
                    link(lx,rx);link(ly,x);link(x,y);
                }
                else if(op==2){
                    link(lx,rx);link(y,x);link(x,ry);
                }
                else if(op==3){
                    //分为两种情形,x,y相邻与否
                    if(right[x]==y){
                        link(lx,y);link(y,x);link(x,ry);
                    }
                    else{
                            link(lx,y);link(y,rx);
                            link(ly,x);link(x,ry);
                    }

                }
            }

        }
        int j=0;
        long long int ans=0;
        for(int i=1;i<=n;i++){
            j=right[j];
            if(i%2==1) ans+=j;
        }
        if(inv && n%2==0) ans=(long long)n/2*(n+1)-ans;
        printf("Case %d: %lld\n",++kase,ans);    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值