链表

最近在看刘汝佳的算法竞赛书, 看到用数组表示链表, 略感特别,所以特此来写篇博客记录一下, 加深印象的同时希望也能记住用法。
基于数组的链表:
思路是每输入一个字符就把它存起来, 设输入字符串是s[1~n], 则可以用next[i]表示在当前显示屏中s[i]右边的字符编号(即在s中的下标).
为了方便起见, 假设字符串s的最前面还有一个虚拟的s[0], 则next[0]就可以表示显示屏中最左边的字符. 再用一个变量cur表示光标位置, 即当前光标位于s[cur]的右边. cur=0说明光标位于"虚拟字符"s[0]的右边, 即显示屏的最左边.为了移动光标, 还需要用一个变量last表示显示屏的最后一个字符是s[last].
思路说起来简单, 但是理解起来倒是不算轻松, 让我们来看看这个算法的核心, next数组, 这里有三个变量, next, i, s, 其中i是索引, s[i]表示当前的字符, next[i]中是下一个字符的在s中的索引, 在这里来看, 很明显, 这是一个链表, next数组就担当了指针的作用. 接下来还有一个小难点, 因为我们是不断读入字符的, 所以next数组在不断放置索引, 也就是说当i = 10的时候, next[1-10]的内容实际上已经固定了, 这个时候如果我们需要移动光标的话, 也就是说遇到’[’, 我们需要做的不是改变next[1-10]的内容, 而是改变next[0]的内容, 让它指向新的位置, 同时不断的读取新的字符, 如果读取完所有的字符或者遇到’]’, 还不能忘了将next的最后一位置为之前的头部, 比如是1, 因为之前没遇到’[‘之前是从1开始输出的。
链表_第1张图片
可以看出来很明显next[0]储存的是开头的字符的索引, 在这里也就是11, 然后我们的打印就会从s[11]开始, 也就是打印’B’, 然后继续, 我们看到next[11]的值是12, 所以我们打印s[12], 也就是’e’, 后面我就不说了, 依次类推, 稍微值得注意的是中间的几个0我省略了没有画出来, 下面是代码。

#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 100000 + 5;
int last, cur, next1[1000005];
char s[maxn];
int main()
{
    while (scanf_s("%s", s + 1) == 1)
    {
        int n = strlen(s + 1);
        last = cur = 0;
        next1[0] = 0;
        for (int i = 0; i <= n; ++i)
        {
            char ch = s[i];
            if (ch == '[')cur = 0;
        else if (ch == ']') cur = last;
            else
            {
                next1[i] = next1[cur];
                next1[cur] = i;
                if (cur == last) last = i;
                cur = i;
            }
        }
        for (int i = next1[0]; i != 0; i = next1[i])
        {
            printf("%c", s[i]);
        }
        cout << endl;
    }
}

这里值得注意的是last是用来保存上一次未遇到’['之前输入的最后一个字符的位置。复杂的算法带来的效率提升也是很明显的, 不仅代码量很小, 算法复杂度也是O(n)。

你可能感兴趣的:(算法,链表)