笔记整理[Shift_And算法及其优化]

2019-03-07  本文已影响0人  六十年目裁判长亚玛萨那度

这属于填年前坑的,毕竟再不做笔记都要长蘑菇了。

首先Shift_and算法它原本长这样

int shift_and(const char *text, const char *pattern) {
    int d[127] = {0}, n = 0;
    for (; pattern[n]; n++) {
        d[pattern[n]] |= (1 << n);// 转换掩码
    }
    int p = 0;
    for (int i = 0; text[i]; i++) {
        p = (p << 1 | 1) & d[text[i]]; // shift_and的精髓在此 相当于是匹配特定位置上的字符 只要母串有模式串有那么相应的就能匹配着
        if (p & (1 << (n - 1))) return 1;//匹配了模式串那么长的就是找到了
    }
    return 0;
}

这是个有图形化实例地方

那么问题来了,这个上面代码中p值,能处理多长的串呢?
答案是32,因为是二进制,一个int型有三十二位可以用。

对吧,这就是问题,你就只能处理个三十二位,是不是太少了?你说long long int型?这治标不治本吧!
那么就要对那个p值做点处理。
既然是数据那就能用数据结构来处理,我们只要把这个值变成任意长度的才能根治这个问题。

有个常见的语言有计算任意长度数值功能,那就是python。

下面的代码是写的特别“质朴”的,为了最优化,借鉴了python的处理实现思想,它比我们的常见的高精度不相同的地方在于,它每个值存的是2的15次方(2的15次方进制的一个数),那么为啥是2的15次方,不是2的32次方呢?因为你可能操作乘法情况啊!会爆掉!
下面的代码有些刚写的时候的注解,之所以没删除是保留一些思路和想法。

它能匹配的字符长度在下面的结构体的数组里设置,1位可处理15字符。最后的函数返回值里出现-1则是没有匹配到,输出非-1的数就是相应匹配成功的串在母串中的下标。

struct object {
    int len;
    int array[20];// 1 : 15 个字符
};
/*************************************************************************
    > File Name: test.c
    > Author: peranda
    > Mail:
    > Created Time: 2019年01月05日 星期六 20时12分59秒
 ************************************************************************/

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

#define OB_SHIFT 15
#define OB_BASH  (1 << OB_SHIFT)
#define OB_MASK  (OB_BASH - 1)

#define TEST(func, a, b) { \
    printf("%s (\"%s\", \"%s\") = %d\n", #func, a, b, func(a, b)); \
}

struct object {
    int len;
    int array[20];// 1 : 15 个字符
};

//结构操作空间的申请和初始化
object* init() {
    object *p = (object *)malloc(sizeof(object));
    p->len = 0;
    return p;
}

//数据的初始化,要处理两种:
//1.是为零的数据
//2.非零正整数
object *init_val(object *p, int value) {
    if (value > 0) { // 传入值大于0
        int i = 0;
        while (value > 0) {
            p->array[i] = value & OB_MASK;
            value >>= OB_SHIFT;
            i += 1;
            p->len += 1;
        }
    } else if (value == 0) { // 传入0
        p->len = 1;
        p->array[0] = 0;
    }
    return p;
}

void output(object *p) {
    printf("output: len = %d\n", p->len);
    int len = p->len;
    while (len > 0) {
        printf("%d ", p->array[len - 1]);
        len -= 1;
    }
    printf("\n");
}

//1.不需要优化结构的数据长度,在数据处于0的时候
//长度len需要为1,并且需要数据为0的存在
//2.如果优化后数据直接无法进行下面的‘&’ 和‘|’操
//作了
/*object *sh_normalize(object *p) {
    int len = p->len;
    while (len > 0 && p->array[len - 1] == 0) {
        --len;
    } 
    p->len = len;
    return p;
}*/

object *zuo_add(object *p, int cnt) { // << 1位
    int len = p->len;
    int carry = 0, i = 0;
    for (; i < len; i++) {
        carry += (p->array[i] << cnt);
        p->array[i] = carry & OB_MASK;
        carry >>= OB_SHIFT;
        //printf("i %d , array = %d\n", i, p->array[i]);
    }
    p->array[i] = carry;
    return p;
    // return sh_normalize(p); 
}

// | 1
object *pan_add(object *p, int cnt) {
    int len = p->len;
    if (len > 0) {
        p->array[0] |= cnt;
    }
    return p;
}

// o & o
object *yu_add(object *p, object *q) {
    int len;
    p->len > q->len ? (len = q->len) : (len = p->len);
    
    while (len > 0) {
        p->array[len - 1] &= q->array[len - 1];
        len -= 1; 
    }
    return p;
}

int yu2_add(object *p, object *q) {
    int len;
    p->len > q->len ? (len = q->len) : (len = p->len);
    
    int o_k = 1;
    // o_k 预设成为1
    while (len > 0) {
        // o_k 会去测试每个2的15次方位, 把每个看做是一个二进制位一样进行&操作
        o_k &= (p->array[len - 1] & q->array[len - 1] ? 1 : 0);
        len -= 1;
    }
    return o_k;
}


int Shift_And(char *str, char *pattern) {
    #define BASE 128 
    int code[BASE] = {0}, len = 0;
    for (len = 0; pattern[len]; len++) {
        code[pattern[len]] |= (1 << len);
    }
    //int p = 0;
    
    object *S = init();
    S = init_val(S, 0);
    //output(S);

    for (int i = 0; str[i]; i++) {
        S = zuo_add(S, 1);
        S = pan_add(S, 1);
        
        object * _code = init();
        _code = init_val(_code, code[str[i]]);
       // printf("code[] = %d\n", code[str[i]]); 
        
        S = yu_add(S, _code);
        //output(S);
        free(_code);

        object * _code1 = init();
        _code1 = init_val(_code1, 1 << (len - 1));
        //output(_code1);
        
        
        /*p = (p << 1 | 1) & code[str[i]];
        printf("p :::::::  %d\n", p);*/

        int o_k = yu2_add(S, _code1);
        printf("yu2_add =  %d \n", o_k);
        if (o_k) {
            printf("end yu2_add =  %d \n", o_k);
            free(S);
            free(_code1);
            return i - len + 1;  
        }

        /*if (p & (1 << (len - 1))) {
            free(S);
            free(_code1);
            return i - len + 1;  
        }*/
        free(_code1);
    }
    free(S);
    return -1;
    #undef BASE
}

int main() {
    char str[100000], pattern[30];
    while (scanf("%s%s", str, pattern) != EOF) {
        TEST(Shift_And, str, pattern);
        bzero(str, strlen(str));
        bzero(pattern, strlen(pattern));
    }
    return 0;
}

--------------------
Shift_And可以处理的字符串是(a|b)c(d|e|f)任意构成的串的,因为和原本的模式串无关

上一篇下一篇

猜你喜欢

热点阅读