Réalisation de cordes
1. Brève introduction
1. Introduction
Le livre dit: "Lorsqu'il s'agit de données de chaîne, c'est beaucoup plus compliqué que de traiter des entiers ou des nombres à virgule flottante, et dans différents types d'applications, les chaînes utilisées ont des caractéristiques différentes. Par conséquent, il est nécessaire d'implémenter efficacement les données de chaîne . Pour y faire face, vous devez utiliser une structure de stockage appropriée en fonction de la situation spécifique. "Je pense que c'est le sens de ce chapitre.
2. Définition de la nature
串
Est une séquence finie composée de zéro ou de plusieurs caractères, généralement enregistrée comme:
s = a 0 a 1 a 2 ··· a n (n> = 0)
s
est le nom de la chaîne; la séquence de caractères entre guillemets simples est The valeur de la chaîne; aIl peut s'agir d'une lettre ou d'autres caractères. Le nombre de caractères d'une chaîne est n
appelé la longueur de la chaîne. Une chaîne de zéro caractère est appelée 空串
.
Dans une chaîne, une séquence de mots composée d'un nombre quelconque de caractères consécutifs est appelée la chaîne 子串
; une chaîne contenant des sous-chaînes est appelée en conséquence 主串
; généralement le numéro de séquence du caractère dans la séquence est appelé la chaîne de la chaîne 位置
. Par
exemple:
s = 'kanna'
b = 'anna'
c = 'kan'
Alors les chaînes b et c sont des sous-chaînes de a, et les longueurs de s, b et c sont respectivement de 5, 4 et 3. La position de b dans s est 2 et la position de c dans s est 1.
Deux. Réalisez
1. Brève chaîne de description
En plus de nos 增删改查
fonctions de base , nous devons concevoir plusieurs fonctions: la longueur de la chaîne; renvoyer une chaîne avec une position et une longueur spécifiées; rechercher une chaîne ...
2. La structure de la chaîne
Il existe une autre structure dans le livre qui utilise un tableau pour représenter une chaîne, mais elle est 堆分配(malloc)
similaire à la nôtre, nous nous concentrons donc sur cette dernière.
Pour la structure de chaîne, nous utilisons deux parties: 用于储存文本的基址区
长度
.
3. Initialisation de la chaîne
Nous pouvons initialiser une chaîne avec un tableau de chaînes de style langage C. ou une valeur littérale de chaîne. La chaîne de style langage C a une caractéristique notable, c'est-à-dire qu'il y en aura un à la fin de la \0
chaîne pour marquer la fin de la chaîne. Utilisez ensuite la commodité pour obtenir la longueur de la chaîne, puis attribuez-la une par une pour initialiser la chaîne d'usurpation.
4. "Ajout" de chaînes
Bien sûr, ajouter une chaîne équivaut à garder la chaîne 1 inchangée, à épisser le contenu de la chaîne 2 derrière la chaîne 1 et à ajouter la longueur de la chaîne 1 à la longueur de la chaîne 2.
5. Comparaison de chaînes
Nous comparons d'abord les longueurs des deux chaînes. Si les longueurs sont différentes, les deux chaînes doivent être différentes. Si la longueur des deux chaînes est la même, alors commencez à comparer le premier caractère, le deuxième caractère ... jusqu'au premier caractère qui n'est pas le même, alors ce n'est pas égal, s'il n'y a pas de caractère différent à la fin , Cela signifie que les deux chaînes sont identiques.
6. Destruction de ficelle
Parce que nos chaînes sont générées dynamiquement, nous pouvons simplement les free
supprimer directement .
7. Chaîne de retour
Nous déplaçons toujours la nôtre 指针
, puis retournons une chaîne assignée séquentiellement.
8. Trouvez une chaîne
Il y a plusieurs façons de trouver une chaîne. Voici un n*m
algorithme de recherche avec un niveau de complexité temporelle . Quant à l'optimisation, c'est le contenu de la section suivante. Notre algorithme de base est le suivant:
Il y a deux pointeurs, le pointeur de sélection a et le pointeur correspondant b.
Nous sélectionnons d'abord le pointeur pour déplacer une position, puis le pointeur correspondant commence à se déplacer. Si le pointeur correspondant déplace la longueur de la chaîne et qu'ils sont tous identiques, la position du pointeur sélectionné a est la position où la chaîne départs. Si le pointeur correspondant se déplace vers une position avant la longueur de la chaîne, cela signifie que la correspondance échoue, sélectionnez le pointeur a ++ et b = a et déplacez à nouveau le pointeur b.
Trois. Code
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
typedef struct sstring{
char *ch;
int len;
}sstring;
sstring* StringInit(char* str);
int StringShow(sstring *str);
int StringConcat(sstring* str1, sstring* str2);
int StringCompare(sstring *str1, sstring *str2);
sstring *StringGet(sstring *str, int index, int len);
int StringFind(sstring *bstr, sstring *mstr);
int main()
{
// 主函数随便改
sstring *test1 = StringInit("bbcd");
sstring *test2 = StringInit("bcd");
//StringConcat(test1, test2);
//printf("%d", StringCompare(test1, test2));
//StringShow(StringGet(test2,0,3));
printf("%d", StringFind(test1,test2));
return 0;
}
sstring* StringInit(char* ss)
{
int lenth = 0;
//首先创建要返回的
sstring *str = (sstring*)malloc(sizeof(sstring));
//动态生成失败,直接退出
if (str == NULL) exit(1);
//如果传入的是空字符串,我们就返回一个空的字符串
if (ss == NULL)
{
str->ch = NULL;
str->len = 0;
return str;
}
// 通过依次遍历,获得传入字符串中,非/0部分长度。
while(*(ss + lenth) != '\0')
{
++lenth;
}
// 修改我们字符串的长度和动态分配它的储存空间
str->len = lenth;
str->ch = (char*)malloc(sizeof(char)*lenth);
--lenth;
// 通过遍历,将C语言字符串的内容,复制到我们的新字符串中
while(lenth >= 0)
{
*(str->ch+lenth) = *(ss+lenth);
--lenth;
}
return str;
}
int StringShow(sstring *str)
{
int ptr = 0;
printf("the string len is %d context is: ", str->len);
while(ptr < str->len)
{
printf("%c", *(str->ch + ptr));
++ptr;
}
printf("\n");
return OK;
}
int StringConcat(sstring* str1, sstring* str2)
{
sstring* stringNew = NULL;
int ptr = 0;
// 如果两个串的长度都是0,那就直接返回即可
if (str1->len + str2->len == 0)
{
return OK;
}
// 否则就先生成我们的新串,修改长度与内容
stringNew = (sstring*)malloc(sizeof(sstring));
stringNew->ch = (char*)malloc(sizeof(char)*(str1->len+str2->len));
stringNew->len = str1->len+str2->len;
// 通过循环,将str1的值写入新串
for(;ptr < str1->len; ++ptr)
{
*(stringNew->ch+ptr) = *(str1->ch+ptr);
}
// 在str1写入新串的基础上,向新串写入str2
for(ptr = 0;ptr < str2->len; ++ptr)
{
*(stringNew->ch+ptr+str1->len) = *(str2->ch+ptr);
}
// 然后这里优点坑,因为传递过来的指针是形参,并不是引用
// 所以 我们只能把新串的值赋值给原来的串
// 此时,传入函数字符串的地址没变,但是len变了, ch的地址变了
*str1 = *stringNew;
return OK;
}
int StringCompare(sstring *str1, sstring *str2)
{
int i = 0;
// 长度都不一样,所以通过长度,反应关系
if (str1->len > str2->len)
{
return 1;
}
else if (str1->len < str2->len)
{
return -1;
}
else
{
// 长度一样了,只有依次对比了
for (; i < str1->len; ++i)
{
// 只要有一个字符不一样,那就根据ascii的关系去返回大小关系
if (*(str1->ch+i) < *(str2->ch+i))
{
return -1;
}
else if (*(str1->ch+i) > *(str2->ch+i))
{
return 1;
}
}
// 循环完了也没有找到不同,所以它俩是一样的
return 0;
}
}
sstring *StringGet(sstring *str, int index, int len)
{
sstring *rstr = NULL;
int i = 0;
// 如果目标串的长度小于我们要求的长度,所以直接返回空的
if (str->len < index+len)
{
return NULL;
}
else
{
// 动态生成我们的返回串
rstr = (sstring *)malloc(sizeof(sstring));
rstr->ch = (char *)malloc(sizeof(char)*str->len);
rstr->len = len;
// 然后把目标串里的值复制到我们的返回串里
for (i = 0; i < len; ++i)
{
*(rstr->ch+i) = *(str->ch+index+i);
}
return rstr;
}
}
int StringFind(sstring *bstr, sstring *mstr)
{
int fptr = 0, lptr = 0;
int mark = 0;
// 如果我们要查找的串的长度大于了目标串,那肯定找不到的,直接返回-1
if (bstr->len < mstr->len)
{
return -1;
}
// lptr是指向 我们目标串的开始指针
// 它只需要从0遍历到(目标串长度-要查找的串的长度)就行了
for (;lptr <= (bstr->len-mstr->len); ++lptr)
{
// mark是标记位,如果有不同,那就是1 没有不同就还是0
mark = 0;
// 这个是查找指针,我们要对比的内容因该是lptr+fptr
// 它的范围是 0到查找串的长度-1
for (fptr = 0; fptr < mstr->len; ++fptr)
{
// 对比的内容是 lptr+fptr
if (*(bstr->ch+lptr+fptr) != *(mstr->ch+fptr))
{
// 有不同,更新标识,并跳出这一轮 fptr的遍历
mark = 1;
break;
}
}
// fptr遍历完了,都还没有不同的,说明找到了
if (mark == 0)
{
// 那么就因该返回我们lptr的起始位置
return lptr;
}
}
// 查遍了整个串都没找到,那就只能返回 -1了
return -1;
}