1. 程式人生 > >資料結構(四)--字串操作

資料結構(四)--字串操作

字串

1.串的定義

串是由零個或多個字元組成的有限序列,一般記為

s=a1a2an
串中任意個連續的字元組成的子序列稱為該串的子串。包含子串的串稱為主串

串的原子操作(其餘操作可以以下操作組合完成)包含以下5種:

  1. 串賦值StrAssign
  2. 串比較StrCompare
  3. 求串長StrLength
  4. 串連線Concat
  5. 求子串SubString

2. 串的表示與實現

串有3種表示方式:

  1. 定長順序儲存(定長)
  2. 堆分配儲存(順序表)
  3. 塊串儲存(連結串列)

2.1 定長順序儲存

定長順序儲存用一組地址連續的儲存單元儲存字元序列。其定義如下

//----------------定長順序儲存------------
/**
 * 定長串約定:
 * 1.0號下表表示為串長
 * 2.當串長長度超過MAX_SIZE時進行截斷
 */
#define MAX_SIZE  255
typedef unsigned char SString[MAX_SIZE + 1 + 1];        //0號下標儲存字串的長度,C語言特性字串最後一個尾'\0'

下面來分別實現上述5個原子操作:

2.1.1串賦值StrAssign

/**
 * 字串分配,將str分配到T中
 * @param T
 * @param str
 * @return
*/
Status strAssign(SString &T,char *str){ int length = 0; char *p_c = str; for(;*p_c!='\0';length++,p_c++); //求字串str的長度 if(length > MAX_SIZE){ T[0] = MAX_SIZE; for(int i = 1;i<=MAX_SIZE;i++){ //超過maxsize的進行截斷 T[i] = str[i-1]; } T[T[0
] + 1] = '\0'; }else{ T[0] = length; for(int i = 1;i<=length;i++){ T[i] = str[i-1]; } T[T[0] + 1] = '\0'; } return OK; }

2.1.2 串比較StrCompare

/**
 * 比較S和T
 * @param S
 * @param T
 * @return  S>T 返回>0
 *          S<T 返回<0
 *          S=T 返回0
 */
Status strCompare(SString &S, SString &T){
    for(int i = 0;i<S[0] && i<T[0];i++){
        if(S[i+1] != T[i+1]) return S[i+1] - T[i+1];
    }
    return S[0] - T[0]; //某一個串是另一串的子串時,比較哪個串更長
}

2.1.3 求串長

/**
 * 求串長
 * @param S
 * @return
 */
int strLength(SString &S){
    return S[0];
}

2.1.4 串連線Concat

/**
 * 串連線,將S1和S2拼接成新串T。
 * 由於定長串固有的缺點,分為以下三種情況:
 * 1.S1,S2在拼接過程中均未截斷
 * 2.S1,S2在拼接過程中S2被截斷
 * 3.S1,S2在拼接過程中S1和S2均被截斷(S1部分截斷,S2全部截斷)
 * @param T
 * @param S1
 * @param S2
 * @return OK
 *
 */
Status Concat(SString &T,SString S1,SString S2){
    if(S1[0] + S2[0] <= MAX_SIZE){
        T[0] = S1[0] + S2[0];
        for(int i = 1;i<=S1[0];i++){
            T[i] = S1[i];
        }
        for(int i = 1+S1[0];i<= S1[0]+S2[0];i++){
            T[i] = S2[i - S1[0]];
        }
        T[T[0] + 1] = '\0';
    }else if(S1[0] <= MAX_SIZE){
        T[0] = MAX_SIZE;
        for(int i = 1;i<=S1[0];i++){
            T[i] = S1[i];
        }
        for(int i = 1+S1[0];i<=MAX_SIZE;i++){
            T[i] = S2[i-S1[0]];
        }
        T[T[0] + 1] = '\0';
    }else{
        T[0] = MAX_SIZE;
        for(int i =1;i<=MAX_SIZE;i++){
            T[i] = S1[i];
         }
        T[T[0] + 1] = '\0';
    }
    return OK;
}

2.1.5 求子串SubString

/**
 * 求S的一個子串,其位置在pos->pos+len-1
 * @param Sub
 * @Param S
 * @param pos
 * @param len
 * @return
 */
Status SubString(SString &Sub,SString S,int pos,int len){
    //判定位置
    if(pos<1 || pos> S[0] || len <0 || pos+len -1 > S[0]) exit(ERROR);
    Sub[0] = len;
    for(int i = 1;i<=len;i++){
        Sub[i] = S[i+pos-1];
    }
    Sub[Sub[0] + 1] = '\0';
    return OK;
}

2.2 堆分配儲存表示

在順序儲存結構中,實現串操作的源操作為“字元序列的賦值”,操作的時間複雜度基於賦值的字元序列的長度。另一操作特點是,如果在操作中出現串序列超過上界,會出現截斷的情況,為客服這個缺點,可通過動態分配串值得儲存空間。基於堆分配儲存的定義如下:

//---------------堆分配字串------------
typedef struct{
    char *ch;
    int length;
}HString;

下面來實現5個原子操作:

2.2.1 串賦值StrAssign

/**
 * 分配
 * @param T
 * @param chars
 * @return
 */
Status StrAssign(HString &T,char *chars){
    if(T.ch) free(T.ch); T.ch = NULL;
    int length;
    char *c = chars;
    for(length = 0;*c!='\0';c++,length++);     //求chars長度
    if(!length){
        T.ch = NULL;
        T.length = 0;
    }else{
        T.ch = (char *)malloc(length*sizeof(char));
        if(!T.ch) exit(ERROR);
        for(int i = 0;i<=length;i++){   //取=號是把 '\0'也放進去
            T.ch[i] = chars[i];
        }
        T.length = length;
    }
    return OK;
}

2.2.2 串比較StrCompare

/**
 * 字串比較
 * @param S
 * @param T
 * @return
 */
int strCompare(HString S,HString T){
    for(int i = 0;i<S.length&&i<T.length;i++){
        if(S.ch[i] != T.ch[i]) return S.ch[i] - T.ch[i];
    }
    return S.length - T.length;
}

2.2.3 求串長

/**
 * S長度
 * @param S
 * @return
 */
int strLength(HString &S){
    return S.length;
}

2.2.4 串連線Concat

/**
 * 字串連線
 * @param T
 * @param S1
 * @param S2
 * @return
 */
Status Concat(HString &T,HString S1,HString &S2){
    if(T.ch) free(T.ch); T.ch = NULL;
    T.ch = (char *)malloc((S1.length+S2.length)*sizeof(char));
    if(!T.ch) exit(ERROR);
    for(int i = 0;i<S1.length;i++){
        T.ch[i] = S1.ch[i];
    }
    for(int i = S1.length;i<=S1.length+S2.length;i++){
        T.ch[i] = S2.ch[i-S1.length];
    }
    T.length = S1.length+S2.length;
    return OK;
}

2.2.5 求子串SubString

Status SubString(HString &Sub,HString S,int pos,int len){
    //位置判定
    if(pos<1 || pos>S.length || len <0 || pos+len -1 > S.length) exit(ERROR);
    if(Sub.ch) free(Sub.ch); Sub.ch = NULL;
    if(!len){
        Sub.ch = NULL;
        Sub.length = 0;
    }else{
        Sub.ch = (char *)malloc(len*sizeof(char));
        for(int i = 0;i<len;i++){
            Sub.ch[i] = S.ch[i+ pos-1];
        }
        Sub.length = len;
        Sub.ch[Sub.length -1] = '\0';
    }
    return OK;
}

2.3 塊鏈

塊鏈的操作不如上述兩種結構方便,且佔用儲存量大,這裡不做討論。

3. KMP演算法

子串的定位操作通常稱做串的模式匹配,可以採用暴力尋找,不過這樣的時間複雜度過高,最為經典的演算法是KMP演算法。網上關於該演算法的文章有很多很多,不過目前我所看到最通俗易懂的是這篇,有需要的朋友可以去看看。

4.總結

字串的處理作為一種非常重要的處理方式被廣泛使用,雖然現在最多高階語言都封裝了String類(如Java,C++等),不過作為一種知識的補充也算是非常不錯的。嗯,就這樣吧。

相關推薦

資料結構--字串操作

字串 1.串的定義 串是由零個或多個字元組成的有限序列,一般記為 s=′a1a2…a′ns=′a1a2…an′ 串中任意個連續的字元組成的子序列稱為該串的子串。包含子串的串稱為主串。 串的原子操作(其餘操作可以以下操作組合完成)包含以下5種:

大話資料結構——雙向連結串列的java實現

在實現了單向連結串列後,我們在使用單向連結串列中會發現一個問題:在單向連結串列中查詢某一個結點的下一個結點的時間複雜度是O(1),但是查詢這個結點的上一個結點的時候,時間複雜度的最大值就變成了O(n),因為在查詢這個指定結點的上一個結點時又需要從頭開始遍歷。 那麼該如何解決這個困難呢?

資料結構佇列

一、基本概念 1、特點: 在佇列頭部進行刪除,在佇列的尾部進行插入操作 2、主要實現: 使用迴圈陣列 使用連結串列 3、關係圖: 二、Queue public interface Queue<E> extends

基礎演算法與資料結構最短路徑——Dijkstra演算法

一般最短路徑演算法習慣性的分為兩種:單源最短路徑演算法和全頂點之間最短路徑。前者是計算出從一個點出發,到達所有其餘可到達頂點的距離。後者是計算出圖中所有點之間的路徑距離。 單源最短路徑 Dijkstra演算法 思維 本質上是貪心的思想,宣告一個數組dis來儲存源點到各個頂點的最短距離和一個儲存已經

資料結構之二叉樹

二叉樹 二叉樹可以用陣列和鏈式結構這兩種方式來建立,這裡只介紹二叉樹的鏈式結構,並且實現二叉樹的前序、中序和後序遍歷。(運用二叉樹組定義靜態二叉樹的方式以註釋的形式寫明) 二叉樹的建立有三種方式:前序、中序和後序。這裡只展現了前序遍歷的方式。 #include<

再談資料結構:排序與查詢

1 - 引言 雖然C++中的STL庫中提供了許多排序和查詢的方法。但是我們還是需要了解一下排序和查詢內部的原理,下面讓我們學習一下各類排序與查詢演算法 2 - 歸併排序 第一種高效的排序演算法是歸併排序,按照分治三步法,對歸併排序演算法介紹如下: 劃分問題:把序列分成

資料結構二叉樹的遍歷

二叉樹的遍歷 0. 樹的表示 typedef struct TreeNode *BinTree; struct TreeNode{ int Data; // 存值 BinTree Left; // 左兒子結點 BinTree Right;

自己動手實現java資料結構雙端佇列

自己動手實現java資料結構(四)雙端佇列 1.雙端佇列介紹   在介紹雙端佇列之前,我們需要先介紹佇列的概念。和棧相對應,在許多演算法設計中,需要一種"先進先出(First Input First Output)"的資料結構,因而一種被稱為"佇列(Queue)"的資料結構被抽象了出來(因為

資料結構C++動態儲存分配

1.運算子new 要為一個整數動態分配儲存空間,可以用下面的語句說明一個整型指標變數int *x;當需要使用該整型時,可用下面的語句為它分配儲存空間: y=new int; 為了在剛分配的空間中儲存一個整數值10, *y=10; int

資料結構之非遞迴遍歷二叉樹

void Inoder(Bitree root)//二叉樹的中序遍歷非遞迴 { IniStack(&S);//初始化一個棧 p=root; while(!isEmpty(S)||p!=NULL) { if(p!=NULL)//如果當前結點不為空進棧 { pu

資料結構——線性結構之佇列Queue

1.佇列 佇列是先進先出的線性表。只允許在表的一端進行插入操作,而在另一端進行刪除操作。 進行插入的一端稱為隊尾,進行刪除操作的一端稱為隊頭。 在具體應用中通常用連結串列或者陣列來實現。 2.對佇列的操作 佇列我們可以想像成一個數組,每次插入插入在陣列的最後一位,取從第一位

資料結構python使用順序表實現棧

概念: 棧(stack),有些地方稱為堆疊,是一種容器,可存入資料元素、訪問元素、刪除元素,它的特點在於只能允許在容器的一端(稱為棧頂端指標,英語:top)進行加入資料(英語:push)和輸出資料(英語:pop)的運算。沒有了位置概念,保證任何時候可以訪問、刪除的元素都是此前最後存入的那個元

挖掘演算法中的資料結構:堆排序之 二叉堆Heapify、原地堆排序優化

不同於前面幾篇O(n^2)或O(n*logn)排序演算法,此篇文章將講解另一個排序演算法——堆排序,也是此係列的第一個資料結構—–堆,需要注意的是在堆結構中排序是次要的,重要的是堆結構及衍生出來的資料結構問題,排序只是堆應用之一。 此篇涉及的知識點有: 堆

資料結構線性表的邏輯結構單鏈表的基本操作的實現

一、 實驗目的1. 掌握線性表的邏輯結構;2. 連結串列的基本操作的實現;3. 掌握利用C++/C程式語言實現資料結構的程式設計方法;4. 通過上機時間加強利用資料結構解決實際應用問題的能力;二、 實驗要求1. 實驗前做好充分準備,包括複習線性表所學內容,事先預習好本次實驗內

資料結構:順序表的基本操作 C語言

順序表   標頭檔案: Sqlist.h #include<stdio.h> #include<stdlib.h> #define SIZE 15 #pragma once typedef struct Sqlist { int elem[SIZ

java資料結構----------順序表操作例項

import java.util.Scanner; class DATA{//資料類 String key; // 節點的關鍵字 String name; String age; } class SLType{// 定義順序表的結構陣列 static fina

SIMD資料並行——三種結構的比較

在計算機體系中,資料並行有兩種實現路徑:MIMD(Multiple Instruction Multiple Data,多指令流多資料流)和SIMD(Single Instruction Multiple Data,單指令流多資料流)。其中MIMD的表現形式主要有多發射、多執行緒、多核心,在當代設計的以處

資料結構——樹結構(Tree) 之二叉樹的常用操作

一.鏈式儲存的二叉樹的操作 1.遍歷二叉樹 先序遍歷:根-->左-->右 中序遍歷:左-->根-->右 後序遍歷:左-->右-->根 2.二叉樹結點的查詢  結點的查詢也可以分為先序查詢,中序查詢和後序查詢。方式和遍

資料結構---基本的棧的操作

棧的基本操作 在這周自己學了一下簡單的棧的基本操作,對棧有了個基本的瞭解,就比如說,在程式裡記憶體分為靜態記憶體和動態記憶體,這兩者的區別是,靜態記憶體是放在棧裡的,由系統分配記憶體的;動態記憶體是存放在堆裡,由程式設計師手動給的。 棧的本質來講這是一種儲存

小白學 Python 資料分析5:Pandas 基礎操作1檢視資料

在家為國家做貢獻太無聊,不如跟我一起學點 Python 人生苦短,我用 Python 前文傳送門: 小白學 Python 資料分析(1):資料分析基礎 小白學 Python 資料分析(2):Pandas (一)概述 小白學 Python 資料分析(3):Pandas (二)資料結構 Series