数据结构笔记整理第4章:字符串和矩阵

第4章 字符串和矩阵

本章内容

本章主要介绍字符串以及数据结构中矩阵的相关内容。

4.1 字符串的基本概念

串的基本概念:串是由零个或者多个字符组成的有限序列。串中字符的个数称为串的长度,含有零个元素的串叫做空串。

串的长度问题:现在看一个例子:
我们声明了一个字符串str,并对其进行赋值:

char str[] = "abcdef";

串通常由一个字符数组来表示,因此在这里str所占的内存字符为:a,b,c,d,e,f,\0,其中\0是编译器识别串结束。而串内字符为:a,b,c,d,e,f。因此,串str的长度为6,数组str的长度为7。

4.2 字符串的定义与相应算法

我们提到的字符串主要由字符数组来实现,因此算法的方式与顺序栈、顺序队列等结构相似。
【定义1】串的定义

#define maxSize 100     //定义串的最大长度为100
typedef struct Str {
    cbar ch[maxSize+1]; //存放元素的字符数组,多一个用来存放\0
    int length;         //串顶指针
}Str;

串的匹配算法。这里我们介绍两种算法,第一种是非常简单的模式匹配算法,第二种是KMP算法。两种算法都是用来判断子串是否为主串的一个部分。如果是则返回其在主串中的位置,不是则返回-1。

【算法1】简单匹配算法
算法的基本思想非常简单:从主串的第一个位置起和子串的第一个字符开始比较,如果相等,则继续逐一比较后面的字符,否则就从主串接下来的字符按照相同的方法开始比较,以此类推直到比较完主串所有的字符。

int index(Str str, Str substr) {
    int i = 0, j = 0, k = i;
    while(i < str.length && j < substr.length) {
        if (str.ch[i] == substr.ch[j]) {
            ++i;
            ++j;
        }
        else {
            j = 0;
            i = ++k;
        }
    }   
    if (j == substr.length) {
        return k;
    }
    return k-1;
}

**【算法2】**KMP算法
KMP算法的核心理念是充分利用已经改进计算过的结果,不回溯i。想办法通过调整j的位置从而消除i处的不匹配,从而使得匹配可以继续进行。
求next数组:假设S串长度为n,下标范围0~n-1,穷举所有串对a和b,a为0~k-1的子串,b为n-k~n-1的子串,a与b匹配。取最长的一个串作为结果,即next[n] = k
由于考研中对KMP算法掌握要求很低,这里就只给出其源码,关于算法的详细讲解会另写博客讨论。

#include 
using namespace std;
int KMP(Str str, Str substr, int next[]);
void getNext(Str substr, int next[]);

int main() {
    Str str = "ABABABABABABAAAA";
    Str substr = "BABA";
    int next[maxSize];
    getNext(substr, next);
    int result = KMP(str, substr, next);
    return 0;
}


int KMP(Str str, Str substr, int next[]) {
    int i = 0, j = 0;
    while(i < str.length && j < substr.length) {
        if (str.ch[i]==substr.ch[j]) {
            ++i;
            ++j;
        }
        else {
            j = next[j];
            if (j == -1) {
                j = 0;
                ++i;
            }
        }
    }
    if (j == substr.length) {
        return i-substr.length;
    }
    return -1;
}

void getNext(Str substr, int next[]) {
    int i = 0, j = -1;
    next[0] = -1;
    while(i < substr.length) {
        if (j == -1 || substr.ch[i] == substr.ch[j]) {
            ++i;
            ++j;
            next[i] = j;
        }
        else {
            j = next[j];
        }
    }
}

4.3 矩阵

这里提到的矩阵主要是指二维的数组,我们会介绍矩阵的一些常见算法和稀疏矩阵的概念。

4.3.1 矩阵的运算

【算法3】矩阵的转置

void transMat(int A[][max], int B[][max], int m, int n) {
    int i, j;
    for (i = 0; i < m; ++i) {
        for (j = 0; j < n; ++j) {
            B[j][i] = A[i][j];
        }
    }
}

【算法4】矩阵相加

void addMat(int C[][max], int A[][max], int B[][max], int m, int n) {
    int i, j;
    for (i = 0; i < m; ++i) {
        for (j = 0; j < n; ++j) {
            C[i][j] = A[i][j] + B[i][j];
        }
    }
}

【算法5】矩阵相乘

void mulMat(int C[][max], int A[][max], int B[][max], int m, int n, int k) {
    int i, j, h;
    for (i = 0; i < m; ++i) {
        for (j = 0; j < n; ++j) {
            C[i][j] = 0;
            for (h = 0; h < k; ++h) {
                C[i][j] += A[i][h] * B[h][j];
            }
        }
    } 
}
4.3.2 稀疏矩阵

尺寸为m*n的矩阵A有K个非零的元素,若K << m*n,则称A为稀疏矩阵。

三元组表示法:

typedef struct Trimat {
    int value;
    int i;
    int j;
}Trimat;
Triamat trimat[5];
trimat[k].val   //第K个非零元素的值
trimat[K].i, trimat[K].i    //第K个非零元素在矩阵中的下标

伪地址表示法:
按照行优先或者列优先,存储相对位置。需要2N个存储单元,N为非零元素的个数。对于一个m*n的稀疏矩阵中元素A[i][j]的伪地址计算方法:
n(i-1)+j,伪地址除以n得到i,取余得到j

邻接表表示法:
链式存储,每一行的非零元素串联成一个链表,不常考察。

你可能感兴趣的:(数据结构)