c语言数据结构-串

简介: c语言数据结构-串

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)

目录

初识串:

串的顺序储存结构:

给顺序串赋值:

串的链式储存结构:

给链串赋值:

串的模式匹配算法:

算法目的:

算法种类:

BF算法:

KMP算法:


初识串:

定义:

零个或多个字符组成的有限序列。

当串长n=0时,又称为空串

串还有其他的基本概念,如下所示:

主串:                a='BEI JING'

子串 :               b='BEI',

                          c='JING'

字符位置 :       从1开始      

串相等 :          d='BEI JING'

空格串 :           e=' '

串的顺序储存结构:

串的顺序存储结构是用一组地址连续的存储单元来存储串中的字符序列的。

注意:

“ \ 0” 用来表示串值的终结,计算串值长度时不计。

/** 串的堆式顺序存储结构(Heap) */
typedef struct 
{
    char* ch;      //如果是非空串,那么就按照指定长度分配内存,否则ch就指向NULL
    int length;     //串的当前长度
}HString;
/** 初始化堆字符串 */
void InitString_HeapString(HString* str)
{
    str->ch = NULL;
    str->length = 0;
}

给顺序串赋值:

/** 为串str赋值,值为字符串常量chars */
int StrAssign_HeapString(HString* str, char* chars)
{
    int len = strlen(chars);
    if (!len) 
    {
        return 0;
    }
    InitString_HeapString(str);
    str->ch = (char*)malloc(len * sizeof(char));
    if (!str->ch)
    {
        exit(-2);
    }
    for (int i = 0; i < len; i++) 
    {
        str->ch[i] = chars[i];
    }
    str->length = len;
    return 1;
}

串的链式储存结构:

优点:操作方便

缺点:存储密度较低(存储密度 = 串值所占的存储位/实际分配的存储位 )

如图所示,链串由块数据和指针构成,而块数据的大小可以自定义

#define BLOCK_SIZE 80   //定义块的大小,可自行修改
/** 块的定义 */
typedef struct block
{
    char ch[BLOCK_SIZE];    //块数据
    struct block* next;    //指向下一个块的指针
}Block;
/** 串的链式存储结构 */
typedef struct
{
    Block* head;   //串的头指针
    Block* tail;   //串的尾指针
    int length;     //串的当前长度
}LString;   //LinkedString的缩写
/** 初始化链串 */
void InitString_LinkedString(LString* str)
{
    str->head = NULL;
    str->tail = NULL;
    str->length = 0;
}

给链串赋值:

/** 为链串str赋值,值为字符串常量chars */
int StrAssign_LinkedString(LString* str, char* chars)
{
    int len = strlen(chars);
    if (!len)
        return 0;
    InitString_LinkedString(str);
    //计算出块的总数:假设长度96,那么就需要有1个块零16个字符
    int block_count = (len + 1) / BLOCK_SIZE; //len+1是因为最后要赋值'\0'表示字符串的结束
    //余下的字符总数
    int surplus_count = (len + 1) % BLOCK_SIZE;
    if (surplus_count > 0) 
    {
        block_count++;  //如果有余下的字符,就需要多一个块来存放
    }
    Block* block;
    for (int i = 1; i <= block_count; i++) 
    {
        block = (Block*)malloc(sizeof(Block));
        if (!block) exit(-2);
        block->next = NULL;
        //在每个块中复制对应的字符
        int count = 0;
        for (; count < BLOCK_SIZE && (count + (i - 1) * BLOCK_SIZE < len); count++)
        {
            //count为当前块要复制的字符个数
            //(i - 1) * BLOCK_SIZE 为 第i个块之前的字符总数
            block->ch[count] = chars[count + (i - 1) * BLOCK_SIZE]; //逐个字符复制
        }
        if (i == block_count) 
        {
            //最后一个块
            block->ch[count] = '\0';
        }
        if (i == 1) 
        {
            //如果是第一个块,链串首尾指针都指向这个块
            str->head = str->tail = block;
        }
        else
        {
            //如果不是第一个块,就需要连接这个块
            str->tail->next = block;    //当前链尾的next指向block
            str->tail = block;          //链尾再修改为block - 链表的常用操作
        }
    }
    str->length = len;
    return 1;
}

串的模式匹配算法:

算法目的:

确定主串中所含字串第一次出现的位置

实现串的定位操作——Index(S,T,pos)函数  

算法种类:

BF算法:

又称古典的、经典的、朴素的、穷举的

BF算法思路:主串子串(又称模式串)都从a开始比较,若两者相同,则i++,j++,两者共同向后比较,当到达第三个元素位置时,两者不相同,此时主串i退回到b的位置(i指针回溯),j则退回到a的位置,重新比较,直到两者比较的元素均相同

/** 串的堆式顺序存储结构(Heap) */
typedef struct
{
    char* ch;      //如果是非空串,那么就按照指定长度分配内存,否则ch就指向NULL
    int length;     //串的当前长度
}HString;
/** 初始化堆字符串 */
void InitString_HeapString(HString* str)
{
    str->ch = NULL;
    str->length = 0;
}
/** 使用暴风算法返回子串在主串中的位置 */
int BFCompare(HString* parent, HString* child, int pos)
{
    int i = pos;    //i用于主串parent中的起始位置
    int j = 1;      //子串的起始位置
    while (i <= parent->length && j <= child->length)
    {
        //i和j都为初始位置,在数组中要-1才能表示其下标
        if (parent->ch[i - 1] == child->ch[j - 1])
        {
            i++;
            j++;
        }
        else 
        {
            i = i - j + 2;  //i回朔到上次匹配的首位的下一位
            j = 1;          //j回到子串的第一个位置
        }
    }
    //当j大于子串长度,说明匹配成功,返回主串中第一个相同元素的下标
    if (j > child->length) 
    {
        return i - child->length;
    }
    return 0;
}

KMP算法

特点:速度快

思路如下:

      匹配过程中出现字符比较不等

   不回溯主指针 i

    利用已得到的“部分匹配”结果将模式向右滑动尽可能远的一段距离

注意:如果有多个匹配字符,则用最远的那一个

那么部分匹配是指哪些部分呢?

前缀:除了最后一个字符外,一个字符串的全部头部组合

后缀:除了第一个字符外,一个字符串的全部尾部组合

部分匹配值(最大共有长度)具体算法如下:

/** 串的堆式顺序存储结构(Heap) */
typedef struct 
{
    char* ch;      //如果是非空串,那么就按照指定长度分配内存,否则ch就指向NULL
    int length;     //串的当前长度
}HString;
/** 初始化堆字符串 */
void InitString_HeapString(HString* str) 
{
    str->ch = NULL;
    str->length = 0;
}
/** 返回next数组(部分匹配表) */
void Get_Next(HString child, int* next) 
{
    int i = 0;
    int j = -1;//用j来统计最大匹配长度
    next[0] = -1;
    while (i < child.length) 
    {
        if (j == -1 || child.ch[i] == child.ch[j]) 
        {
            i++;
            j++;
            next[i] = j;
        }
        else 
        {
            j = next[j];
        }
    }
}
/** 使用KMP算法进行比较,返回子串在主串中的位置 */
int KMPCompare(HString* parent, HString* child, int pos) 
{
    int next[255];  //用来存放部分匹配值
    Get_Next(*child, next); //首先处理子串,计算出部分匹配值
    int i = pos - 1;
    int j = 0;
    while (i < parent->length && j < child->length) 
    {
        if (j == -1 || parent->ch[i] == child->ch[j]) 
        {
            i++;
            j++;
        }
        else 
        {
            j = next[j];
        }
    }
    if (j == child->length) 
    {
        return (i + 1) - j;
    }
    return 0;
}


相关文章
|
3天前
|
存储 算法 C语言
通义灵码在考研C语言和数据结构中的应用实践 1-5
通义灵码在考研C语言和数据结构中的应用实践,体验通义灵码的强大思路。《趣学C语言和数据结构100例》精选了五个经典问题及其解决方案,包括求最大公约数和最小公倍数、统计字符类型、求特殊数列和、计算阶乘和双阶乘、以及求斐波那契数列的前20项和。通过这些实例,帮助读者掌握C语言的基本语法和常用算法,提升编程能力。
|
3天前
|
存储 算法 C语言
【趣学C语言和数据结构100例】
《趣学C语言和数据结构100例》精选5个编程问题,涵盖求最大公约数与最小公倍数、字符统计、特殊序列求和及阶乘计算等,通过实例讲解C语言基础与算法思维,适合初学者实践学习。
|
13天前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
17 2
|
1月前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
222 8
|
1月前
|
C语言
数据结构基础详解(C语言):图的基本概念_无向图_有向图_子图_生成树_生成森林_完全图
本文介绍了图的基本概念,包括图的定义、无向图与有向图、简单图与多重图等,并解释了顶点度、路径、连通性等相关术语。此外还讨论了子图、生成树、带权图及几种特殊形态的图,如完全图和树等。通过这些概念,读者可以更好地理解图论的基础知识。
|
1月前
|
存储 算法 C语言
数据结构基础详解(C语言): 二叉树的遍历_线索二叉树_树的存储结构_树与森林详解
本文从二叉树遍历入手,详细介绍了先序、中序和后序遍历方法,并探讨了如何构建二叉树及线索二叉树的概念。接着,文章讲解了树和森林的存储结构,特别是如何将树与森林转换为二叉树形式,以便利用二叉树的遍历方法。最后,讨论了树和森林的遍历算法,包括先根、后根和层次遍历。通过这些内容,读者可以全面了解二叉树及其相关概念。
|
1月前
|
存储 算法 C语言
数据结构基础详解(C语言):单链表_定义_初始化_插入_删除_查找_建立操作_纯c语言代码注释讲解
本文详细介绍了单链表的理论知识,涵盖单链表的定义、优点与缺点,并通过示例代码讲解了单链表的初始化、插入、删除、查找等核心操作。文中还具体分析了按位序插入、指定节点前后插入、按位序删除及按值查找等算法实现,并提供了尾插法和头插法建立单链表的方法,帮助读者深入理解单链表的基本原理与应用技巧。
308 6
|
1月前
|
存储 C语言 C++
数据结构基础详解(C语言) 顺序表:顺序表静态分配和动态分配增删改查基本操作的基本介绍及c语言代码实现
本文介绍了顺序表的定义及其在C/C++中的实现方法。顺序表通过连续存储空间实现线性表,使逻辑上相邻的元素在物理位置上也相邻。文章详细描述了静态分配与动态分配两种方式下的顺序表定义、初始化、插入、删除、查找等基本操作,并提供了具体代码示例。静态分配方式下顺序表的长度固定,而动态分配则可根据需求调整大小。此外,还总结了顺序表的优点,如随机访问效率高、存储密度大,以及缺点,如扩展不便和插入删除操作成本高等特点。
156 5
|
1月前
|
存储 机器学习/深度学习 C语言
数据结构基础详解(C语言): 树与二叉树的基本类型与存储结构详解
本文介绍了树和二叉树的基本概念及性质。树是由节点组成的层次结构,其中节点的度为其分支数量,树的度为树中最大节点度数。二叉树是一种特殊的树,其节点最多有两个子节点,具有多种性质,如叶子节点数与度为2的节点数之间的关系。此外,还介绍了二叉树的不同形态,包括满二叉树、完全二叉树、二叉排序树和平衡二叉树,并探讨了二叉树的顺序存储和链式存储结构。
|
1月前
|
存储 C语言
数据结构基础详解(C语言): 栈与队列的详解附完整代码
栈是一种仅允许在一端进行插入和删除操作的线性表,常用于解决括号匹配、函数调用等问题。栈分为顺序栈和链栈,顺序栈使用数组存储,链栈基于单链表实现。栈的主要操作包括初始化、销毁、入栈、出栈等。栈的应用广泛,如表达式求值、递归等场景。栈的顺序存储结构由数组和栈顶指针构成,链栈则基于单链表的头插法实现。
253 3