在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ 數(shù)據(jù)分析&挖掘/ 字符串查找 下篇
hash表
單詞統(tǒng)計
鏈表排序
查找
可變參數(shù)
爬樓梯
內(nèi)存
prim算法 中
線性結(jié)構(gòu)的處理
數(shù)據(jù)選擇
prim算法 上
循環(huán)單向鏈表
基數(shù)排序
堆排序
鏈表重合
排序二叉樹的保存和加載
圖添加和刪除
排序二叉樹線索化
非遞歸排序
字符串查找 下篇
鏈表逆轉(zhuǎn)
函數(shù)堆棧顯示
遞歸和堆棧
二叉樹深度遍歷
線性隊列
循環(huán)和遞歸
快速排序
尋找丟失的數(shù)
A*算法
克魯斯卡爾算法 下
排序二叉樹
大數(shù)計算
二叉樹廣度遍歷
prim算法 下
洗牌算法
圖結(jié)構(gòu)
最大公約數(shù)、最小公倍數(shù)
圖創(chuàng)建
雙向鏈表
字符串查找 上篇
尋路
通用算法的編寫
哈夫曼樹 下
線性堆棧
八皇后
排序二叉樹刪除-1
挑選最大的n個數(shù)
字符串查找 中篇
哈夫曼樹 上
合并排序
回數(shù)
選擇排序
哈希二叉樹
通用數(shù)據(jù)結(jié)構(gòu)
“數(shù)星星”
單向鏈表
排序二叉樹插入
圖的保存
排序二叉樹刪除-2
排序二叉樹刪除-3
n!中末尾零的個數(shù)統(tǒng)計

字符串查找 下篇

前面我們談到了KMP算法,但是講的還不是很詳細。今天我們可以把這個問題講的稍微詳細一點。假設在字符串A中尋找字符串B,其中字符串B的長度為n,字符串A的長度遠大于n,在此我們先忽略。

假設現(xiàn)在開始在字符串A中查找,并且假設雙方在第p個字符的時候發(fā)現(xiàn)查找出錯了,也就是下面的情況:

/*       
*    A: A1 A2 A3 A4 ... Ap ............ 
*    B: B1 B2 B3 B4 ... Bp ...Bn  
*                       (p)         
*/ 

那么這時候,A有什么選擇呢?它可以左移1位,用A2~A(p-1)比較B1~B(p-2),然后再用A(p)~A(n+1)比較B(p-1)~B(n)位;或者左移2位,用A3~A(p-1)比較B1~B(p-3),然后再用A(p)~A(n+2)比較B(p-2)~B(n)位; 依次類推,直到左移(p-2)位,用A(p-1)比較B(1),然后再用A(p)~A(p+n-2)比較B(2)~B(n)位。

不知道細心的朋友們發(fā)現(xiàn)什么規(guī)律沒?因為A和B在前面(p-1)個數(shù)據(jù)是相等的,所以上面的計算其實可以這樣看:用A2~A(p-1)比較B1~B(p-2),實際上就是B2~B(p-1)比較B1~B(p-2); 用A3~A(p-1)比較B1~B(p-3),實際上就是B3~B(p-1)比較B1~B(p-3);最后直到B(p)和B(1)兩者相比較。既然這些數(shù)據(jù)都是B自身的數(shù)據(jù),所以當然我們可以提前把這些結(jié)果都算出來的。

那么這么多的選擇,我們應該左移多少位呢?

其實判斷很簡單。假設我們左移1位,發(fā)現(xiàn)A2~A(p-1)的結(jié)果和B1~B(p-2)是一致的,那么兩者可以直接從第(p-1)位開始比較了; 如果不成功呢,那么只能左移2位,并判斷A2~A(p-1)和B1~B(p-2)的比較結(jié)果了,......,這樣以此類推進行比較。如果不幸發(fā)現(xiàn)所有的數(shù)據(jù)都不能比較成功呢,那么只能從頭再來,從第1位數(shù)據(jù)依次進行比較了。

不知道講清楚了沒,還沒有明白的朋友可以看看下面的代碼:

int calculate_for_special_index(char str[], int index)  
{  
    int loop;  
    int value;  

    value = 0;  
    for(loop = 1; loop < index; loop ++){  
        if(!strncmp(&str[loop], str, (index - loop))){  
            value = index - loop;  
            break;  
        }  
    }  

    return (value == 0) ? 1 : (index - value);  
}  

void calculate_for_max_positon(char str[], int len, int data[])  
{  
    int index;  

    for(index = 0; index < len; index++)  
        data[index] = calculate_for_special_index(str, index);  
}  

當然,上面當然都是為了計算在索引n比較失敗的時候,判斷此時字符應該向左移動多少位。

char* strstr_kmp(const char* str, char* data)  
{  
    int index;  
    int len;  
    int value;  
    int* pData;  

    if(NULL == str || NULL == str)  
        return NULL;  

    len = strlen(data);  
    pData = (int*)malloc(len * sizeof(int));  
    memset(pData, 0, len * sizeof(int));  
    calculate_for_max_positon((char*)str, len, pData);  

    index = 0;  
    while(*str && ((int)strlen(str) >= len)){  
        for(; index < len; index ++){  
            if(str[index] != data[index])  
                break;  
        }  

        if(index == len){  
            free(pData);  
            return (char*) str;  
        }  

        value = pData[index];  
        str += value;  

        if(value == 1)  
            index = 0;  
        else  
            index = index -value;  
    }  

    free(pData);  
    return NULL;  
}  

可能朋友們看到了,上面的strlen又回來了?說明代碼本身還有優(yōu)化的空間。大家可以自己先試一試。

int check_valid_for_kmp(char str[], int start, int len)  
{  
    int index;  

    for(index = start; index < len; index++)  
        if('\0' == str[index])  
            return 0;  
    return 1;  
}  

char* strstr_kmp(const char* str, char* data)  
{  
    int index;  
    int len;  
    int value;  
    int* pData;  

    if(NULL == str || NULL == str)  
        return NULL;  

    len = strlen(data);  
    pData = (int*)malloc(len * sizeof(int));  
    memset(pData, 0, len * sizeof(int));  
    calculate_for_max_positon((char*)str, len, pData);  

    index = 0;  
    while(*str && check_valid_for_kmp((char*)str, index, len)){  
        for(; index < len; index ++){  
            if(str[index] != data[index])  
                break;  
        }  

        if(index == len){  
            free(pData);  
            return (char*) str;  
        }  

        value = pData[index];  
        str += value;  

        if(value == 1)  
            index = 0;  
        else  
            index = index -value;  
    }  

    free(pData);  
    return NULL;  
}  

(三)、多核查找

多核查找其實不新鮮,就是把查找分成多份,不同的查找過程在不同的核上面完成。舉例來說,我們現(xiàn)在使用的cpu一般是雙核cpu,那么我們可以把待查找的字符分成兩份,這樣兩份查找就可以分別在兩個核上面同時進行了。具體怎么做呢,其實不復雜。首先我們要定義一個數(shù)據(jù)結(jié)構(gòu):

typedef struct _STRING_PART  
{  
    char * str;  
    int len;  
}STRING_PART; 

接著,我們要做的就是把字符串分成兩等分,分別運算起始地址和長度。

void set_value_for_string_part(char str[], int len, STRING_PART part[])  
{  
    char* middle = str + (len >> 1);  

    while(' ' != *middle)  
        middle --;  

    part[0].str = str;  
    part[0].len = middle - (str -1);  

    part[1].str = middle + 1;  
    part[1].len = len - (middle - (str - 1));  
}  

分好之后,就可以開始并行運算了。

char* strstr_omp(char str[], char data[])  
{  
    int index;  
    STRING_PART part[2] = {0};  
    char* result[2] = {0};  
    int len = strlen(str);  

    set_value_for_string_part(str, len, part);  

#pragma omp parellel for   
    for(index = 0; index < 2; index ++)  
        result[index] = strstr(part[index].str, part[index].len, data);  

    if(NULL == result[0] && NULL == result[1])  
        return NULL;  

    return (NULL != result[0]) ? result[0] : result[1];  
}  

注意事項:

(1)這里omp宏要在VS2005或者更高的版本上面才能運行,同時需要添加頭文件#include,打開openmp的開關(guān);

(2)這里調(diào)用的strstr函數(shù)第2個參數(shù)是目標字符串的長度,和我們前面介紹的普通查找函數(shù)稍微不一樣,前面的函數(shù)不能直接使用,但稍作改變即可。