【数据结构】之串(C语言描述)
串(字符串)是编程中最常用的结构,但 C语言 中没有“字符串”这种变量,只能通过字符数组的形式表示字符串。
C语言 为我们提供了一个 string.h 的头文件,通过这个头文件,我们可以实现对字符串的各种操作,如拷贝、比较等,具体用法请参考【C语言库函数】。
当然,我们对字符串的操作可能不仅仅局限于 string.h 这个头文件给我们提供的这些方法,因此,我们可以自己实现一个字符串的数据结构,通过在这里面编写一些实用的方法,实现我们的需求。
以下是实用 C语言 编写的一个字符串的头文件 String.h,代码如下:
/**
* 串(顺序存储方式)
* 注意:字符串都是以“\0”符号结尾的
*/
#include <Constant.h> // 定义字符串的数据结构体
typedef struct String {
char* data; // 字符串中的数据
int currLength; // 字符串的当前长度
int maxLength; // 字符串的总长度
} String; // 0.获取某个字符串的长度
int getCharArrayLength(char* string) {
int length = ;
while(string[length] != '\0') {
length++;
}
return length;
} // 1.初始化字符串(创建一个新的字符串,其中包含string中的所有字符)
Status initString(String* S, char* string) {
int i = ;
// 获取字符串的长度
int length = getCharArrayLength(string);
// 字符串赋值
S->data = (char*)malloc(length * sizeof(char));
if(S->data == NULL) {
printf("initString => 空间分配失败,初始化字符串失败!\n");
return FAILURE;
}
S->currLength = length;
S->maxLength = length;
for(i = ; i < length; i++) {
S->data[i] = string[i];
}
return SUCCESS;
} // 2.复制字符串(将字符串string中的所有字符复制到字符串S中)
Status copyString(String* S, char* string) {
int i;
int length = getCharArrayLength(string);
if(S->data == NULL) {
printf("copyString => 字符串不存在,复制失败!\n");
return FAILURE;
}
if(length > S->maxLength) {
S->data = (char*)realloc(S->data, length * sizeof(char));
if(S->data == NULL) {
printf("copyString => 重分配空间失败,复制字符串失败!\n");
return FAILURE;
}
S->maxLength = length;
}
S->currLength = length;
for(i = ; i < length; i++) {
S->data[i] = string[i];
}
return SUCCESS;
} // 3.判断字符串是否为空
Status isStringEmpty(String* S) {
if(S->data == NULL) {
printf("isStringEmpty => 字符串不存在!\n");
exit();
}
if(S->currLength == ) {
return TRUE;
}
return FALSE;
} // 4.比较两个字符串的大小(返回的是S1与S2比较的结果)
// 当两个字符串的长度相等,且对应字符都相同时,称这两个字符串相等;否则,看第一个不相等的字符比较结果,字符较大的字符串较大
Status compareString(String* S1, String* S2) {
int i = ;
// 判空
if(S1->data == NULL || S2->data == NULL) {
printf("compareString => 其中一个字符串不存在!\n");
exit();
}
// 某一个字符串为空
if(S1->currLength == ) {
if(S2->currLength == ) {
return EQUAL;
} else {
return SMALLER;
}
}
if(S2->currLength == ) {
if(S1->currLength == ) {
return EQUAL;
} else {
return BIGGER;
}
}
// 两个字符串都不为空时,逐个字符比较
for(i = ; ;i++) {
if(i == S1->currLength && i == S2->currLength) {
return EQUAL;
}
if(i >= S1->currLength) {
return SMALLER;
}
if(i >= S2->currLength) {
return BIGGER;
}
if(S1->data[i] > S2->data[i]) {
return BIGGER;
} else if(S1->data[i] < S2->data[i]) {
return SMALLER;
}
}
} // 5.获取字符串的长度
int getStringLength(String* S) {
if(S->data == NULL) {
printf("getStringLength => 字符串不存在!\n");
exit();
}
return S->currLength;
} // 6.清空字符串
Status clearString(String* S) {
if(S->data == NULL) {
printf("clearString => 字符串不存在!\n");
return FAILURE;
}
S->currLength = ;
return SUCCESS;
} // 7.将字符串S2连接到字符串S1后面并返回
Status concatString(String* S1, String* S2) {
if(S1->data == NULL || S2->data == NULL) {
printf("concatString => 其中一个字符串不存在!\n");
return FAILURE;
}
int i;
int len1 = getStringLength(S1);
int len2 = getStringLength(S2);
if(S1->maxLength < len1 + len2) {
S1->data = (char*)realloc(S1->data, (len1 + len2) * sizeof(char));
if(S1->data == NULL) {
printf("concatString => 重分配空间失败,字符串拼接失败!\n");
return FAILURE;
}
S1->maxLength = len1 + len2;
}
for(i = ; i < len2; i++) {
S1->data[len1 + i] = S2->data[i];
}
S1->currLength = len1 + len2;
return SUCCESS;
} // 8.返回字符串S中从pos位置开始,长度为len的子串
char* getSubString(String* S, int pos, int len) {
char* result;
int i;
if(S->data == NULL) {
printf("getSubString => 字符串不存在!\n");
exit();
}
if(pos < || pos >= S->currLength) {
printf("getSubString => pos参数超出范围!\n");
exit();
}
if(len > S->currLength - pos) {
printf("getSubString => 子串长度超出范围!\n");
exit();
}
for(i = ; i < len; i++) {
*(result + i) = S->data[pos + i];
}
*(result + i) = '\0';
return result;
} // 9.返回字符串S中从pos位置开始的与子串string相等的第一个子串的位置
int locateSubString(String* S, char* string, int pos) {
int i, j;
int length = getCharArrayLength(string);
if(S->data == NULL) {
printf("locateSubString => 字符串不存在!\n");
exit();
}
if(pos < || pos >= S->currLength) {
printf("locateSubString => pos参数超出范围!");
exit();
}
if(length + pos > S->currLength) {
printf("locateSubString => 子串长度超出范围!\n");
exit();
}
for(i = pos; i <= S->currLength - length; i++) {
for(j = ; j < length; j++) {
if(S->data[i + j] != string[j]) {
break;
}
}
if(j == length) {
return i;
}
}
return -;
} // 10.在字符串S的pos位置插入字符串string
Status stringInsert(String* S, int pos, char* string) {
int i;
int length = getCharArrayLength(string);
if(S->data == NULL) {
printf("stringInsert => 字符串不存在,插入字符失败!\n");
return FAILURE;
}
if(pos < || pos > S->currLength) {
printf("stringInsert => pos参数超出范围,插入字符失败!\n");
return FAILURE;
}
if(S->currLength + length > S->maxLength) {
S->data = (char*)realloc(S->data, (S->currLength + length) * sizeof(char));
if(S->data == NULL) {
printf("stringInsert => 重分配空间失败,插入字符失败!\n");
return FAILURE;
}
S->maxLength = S->currLength + length;
}
for(i = S->currLength - ; i >= pos; i--) {
S->data[i + length] = S->data[i];
}
for(i = ; i < length; i++) {
S->data[pos + i] = string[i];
}
S->currLength += length;
return SUCCESS;
} // 11.删除字符串S中从pos位置开始的len个字符
Status stringDelete(String* S, int pos, int len) {
int i;
if(S->data == NULL) {
printf("stringDelete => 字符串不存在,删除字符失败!\n");
return FAILURE;
}
if(pos < || pos >= S->currLength) {
printf("stringDelete => pos参数超出范围,删除字符失败!\n");
return FAILURE;
}
if(pos + len > S->currLength) {
printf("stringDelete => 子串长度超出范围,删除字符失败!\n");
return FAILURE;
}
for(i = pos + len; i < S->currLength; i++) {
S->data[i - len] = S->data[i];
}
S->currLength -= len;
return SUCCESS;
} // 12.用字符串newStr替换字符串S中出现的所有与子串oldStr相同的不重叠的子串
Status replaceString(String* S, char* oldStr, char* newStr) {
int index;
int oldLen = getCharArrayLength(oldStr);
int newLen = getCharArrayLength(newStr);
if(S->data == NULL) {
printf("replaceString => 字符串不存在,替换失败!\n");
return FAILURE;
}
index = locateSubString(S, oldStr, );
while(index >= && index + oldLen <= S->currLength) {
stringDelete(S, index, oldLen);
stringInsert(S, index, newStr);
if(oldLen + index + newLen >= S->currLength) {
break;
}
index = locateSubString(S, oldStr, index + newLen);
}
return SUCCESS;
} // 13.遍历字符串
void traverseString(String* S) {
int i;
if(S->data == NULL) {
printf("traverseString => 字符串不存在,遍历失败!\n");
exit();
}
printf("遍历字符串:");
for(i = ; i < S->currLength; i++) {
printf("%c", S->data[i]);
}
printf("\n");
} // 14.销毁字符串
Status destroyString(String* S) {
if(S->data == NULL) {
printf("destroyString => 字符串不存在,不需要销毁!\n");
return FAILURE;
}
free(S->data);
S->data = NULL;
S->currLength = ;
S->maxLength = ;
return SUCCESS;
} // 测试函数
int testString() {
// 声明变量
String str1, str2;
// 初始化字符串
if(initString(&str1, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]") == SUCCESS) {
printf("初始化字符串S1成功!\n");
traverseString(&str1); // 遍历
}
if(initString(&str2, "abc") == SUCCESS) {
printf("初始化字符串S2成功!\n");
traverseString(&str2);
}
// 清空字符串
if(clearString(&str2) == SUCCESS) {
printf("清空字符串S2成功!\n");
}
// 判断字符串是否为空
printf("字符串S1是否为空?%s\n", isStringEmpty(&str1) ? "是" : "否");
printf("字符串S2是否为空?%s\n", isStringEmpty(&str2) ? "是" : "否");
// 字符串复制
if(copyString(&str2, "abcdefg") == SUCCESS) {
printf("字符串复制成功!\n");
traverseString(&str2);
}
// 字符串连接
if(concatString(&str1, &str2) == SUCCESS) {
printf("将字符串S2连接到S1后面成功!\n");
traverseString(&str1);
}
// 比较两个字符串的大小
printf("S1比S2的关系?%d\n", compareString(&str1, &str2));
// 字符串的长度
printf("字符串S1的长度:%d\n", getStringLength(&str1));
printf("字符串S2的长度:%d\n", getStringLength(&str2));
// 取字符串的子串
printf("S1从58位置开始7个长度的子串是:%s\n", getSubString(&str1, , ));
// 返回子串第一次出现的位置
printf("字符串S1中从20位置起,ABCDE子串第一次出现的位置是%d\n", locateSubString(&str1, "ABCD", ));
// 插入字符串
if(stringInsert(&str1, , "||||||") == SUCCESS) {
printf("在S1的26位置插入字符串||||||成功!\n");
traverseString(&str1);
}
// 删除字符串
if(stringDelete(&str1, , ) == SUCCESS) {
printf("从S1的26位置删除6个字符成功!\n");
traverseString(&str1);
}
// 替换字符串
if(replaceString(&str1, "abcdefg", "") == SUCCESS) {
printf("成功将S1中的所有abcdefg替换为0123456789!\n");
traverseString(&str1);
}
// 销毁字符串
if(destroyString(&str1) == SUCCESS) {
printf("销毁字符串S1成功!\n");
}
if(destroyString(&str2) == SUCCESS) {
printf("销毁字符串S2成功!\n");
}
return ;
}
常量头文件 Constant.h 中的代码如下:
#include <stdio.h>
#include <stdlib.h> #define TRUE 1
#define FALSE 0 #define SUCCESS 1
#define FAILURE 0 #define SMALLER -1
#define EQUAL 0
#define BIGGER 1 typedef int Status;
主函数所在的文件 main.c 中的代码如下:
#include <String.h> int main() {
testString();
return ;
}
运行结果如下:
初始化字符串S1成功!
遍历字符串:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]
初始化字符串S2成功!
遍历字符串:abc
清空字符串S2成功!
字符串S1是否为空?否
字符串S2是否为空?是
字符串复制成功!
遍历字符串:abcdefg
将字符串S2连接到S1后面成功!
遍历字符串:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]abcdefg
S1比S2的关系?1
字符串S1的长度:65
字符串S2的长度:7
S1从58位置开始7个长度的子串是:abcdefg
字符串S1中从20位置起,ABCDE子串第一次出现的位置是26
在S1的26位置插入字符串||||||成功!
遍历字符串:abcdefghijklmnopqrstuvwxyz||||||ABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]abcdefg
从S1的26位置删除6个字符成功!
遍历字符串:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]abcdefg
成功将S1中的所有abcdefg替换为0123456789!
遍历字符串:0123456789hijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]0123456789
销毁字符串S1成功!
销毁字符串S2成功! Process returned 0 (0x0) execution time : 1.783 s
Press any key to continue.
【数据结构】之串(C语言描述)的更多相关文章
- 数据结构与算法分析——C语言描述 第三章的单链表
数据结构与算法分析--C语言描述 第三章的单链表 很基础的东西.走一遍流程.有人说学编程最简单最笨的方法就是把书上的代码敲一遍.这个我是头文件是照抄的..c源文件自己实现. list.h typede ...
- 最小正子序列(序列之和最小,同时满足和值要最小)(数据结构与算法分析——C语言描述第二章习题2.12第二问)
#include "stdio.h" #include "stdlib.h" #define random(x) (rand()%x) void creat_a ...
- C语言学习书籍推荐《数据结构与算法分析:C语言描述(原书第2版)》下载
维斯 (作者), 冯舜玺 (译者) <数据结构与算法分析:C语言描述(原书第2版)>内容简介:书中详细介绍了当前流行的论题和新的变化,讨论了算法设计技巧,并在研究算法的性能.效率以及对运行 ...
- 数据结构与抽象 Java语言描述 第4版 pdf (内含标签)
数据结构与抽象 Java语言描述 第4版 目录 前言引言组织数据序言设计类P.1封装P.2说明方法P.2.1注释P.2.2前置条件和后置条件P.2.3断言P.3Java接口P.3.1写一个接口P.3. ...
- 《数据结构与算法分析——C语言描述》ADT实现(NO.00) : 链表(Linked-List)
开始学习数据结构,使用的教材是机械工业出版社的<数据结构与算法分析——C语言描述>,计划将书中的ADT用C语言实现一遍,记录于此.下面是第一个最简单的结构——链表. 链表(Linked-L ...
- 《数据结构与算法分析-Java语言描述》 分享下载
书籍信息 书名:<数据结构与算法分析-Java语言描述> 原作名:Data Structures and Algorithm Analysis in Java 作者: 韦斯 (Mark A ...
- 《数据结构与算法分析:C语言描述_原书第二版》CH3表、栈和队列_reading notes
表.栈和队列是最简单和最基本的三种数据结构.基本上,每一个有意义的程序都将明晰地至少使用一种这样的数据结构,比如栈在程序中总是要间接地用到,不管你在程序中是否做了声明. 本章学习重点: 理解抽象数据类 ...
- 读书笔记:《数据结构与算法分析Java语言描述》
目录 第 3 章 表.栈和队列 3.2 表 ADT 3.2.1 表的简单数组实现 3.2.2 简单链表 3.3 Java Collections API 中的表 3.3.1 Collection 接口 ...
- 【数据结构与算法分析——C语言描述】第二章总结 算法分析
算法 算法(algorithm)是为求解一个问题需要遵循的.被清楚地指定的简单指令的集合. 数学基础 四个定义: 1.大O表示法: 如果存在正常数 c 和 n0 使得当 N ≥ n0时,T(N) ≤ ...
- 《数据结构与算法分析——C语言描述》ADT实现(NO.05) : 散列(Hash)
散列(Hash)是一种以常数复杂度实现查找功能的数据结构.它将一个关键词Key,通过某种映射(哈希函数)转化成索引值直接定位到相应位置. 实现散列有两个关键,一是哈希函数的选择,二是冲突的处理. 对于 ...
随机推荐
- 【python3基础】命令行参数及 argparse
目录 命令行参数及 argparse 包 argparse 传递 bool 参数错误做法 argparse 传递 bool 参数正确做法 1 argparse 传递 bool 参数正确做法 2 Ref ...
- 【MySQL】MySQL Workbench快捷键小结
执行当前行,ctrl+enter 执行整篇sql脚本: ctrl+shift+enter 格式化sql语句(美化sql语句):ctrl+b 自动补全:ctrl+space(似乎win10中这个快捷键失 ...
- (JavaScript) JS方式调用POS机蓝牙打印
function print(mac_address) { if (!mac_address) { mui.toast('请选择蓝牙打印机'); return; } main = plus.andro ...
- JAVA中的NIO (New IO)
简介 标准的IO是基于字节流和字符流进行操作的,而JAVA中的NIO是基于Channel和Buffer进行操作的. 传统IO graph TB; 字节流 --> InputStream; 字节流 ...
- 最小生成树两个经典算法(Prime算法、Kruskal算法) - biaobiao88
经典的最小生成树例子,Prime算法,具体的步骤及其注释本人均在代码中附加,请仔细阅读与品味,要求,可以熟练的打出. //Prime算法基础 #include<iostream> usin ...
- [专题总结]2-sat及题目&题解(2/5 complete)
啥啥啥2-sat今天就是最后一天了???我才打两道题啊... %%%yxm永远领先全世界... 为了防止学=没学所以还是要记一下,防止忘也确认自己真正理解了吧. 2-sat是指2适应性问题,然而知道这 ...
- NOIP模拟27
两个机房又和在一起考试 开场看了看T1,感觉挺水的,过. T2,这个式子有点奇怪,暂时没什么思路,过 T3,好像保留最后几位换个根处理一下就行了,过,先去打T1 于是T1大概打了0.5h,连暴力带正解 ...
- 8.1 NOIP模拟11
8.1 NOIP模拟 11 今天上午返校之后,颓了一会,然后下午就开始考试,中午睡着了,然后刚开始考试的时候就困的一匹,我一看T1,woc,这不是之前线段树专题的题啊,和那道题差不多,所以我..... ...
- L1与L2正则化的对比及多角度阐述为什么正则化可以解决过拟合问题
正则化是一种回归的形式,它将系数估计(coefficient estimate)朝零的方向进行约束.调整或缩小.也就是说,正则化可以在学习过程中降低模型复杂度和不稳定程度,从而避免过拟合的危险. 一. ...
- Flink中异步AsyncIO的实现 (源码分析)
先上张图整体了解Flink中的异步io 阿里贡献给flink的,优点就不说了嘛,官网上都有,就是写库不会柱塞性能更好 然后来看一下, Flink 中异步io主要分为两种 一种是有序Ordered 一种 ...