• 第 4 章 串(串的堆分配存储实现)


    1. 背景说明

    实现基本与定长分配一致,不过将定长分配改为动态分配,解除了长度限制,实现更加灵活。

    2. 示例代码

    1) status.h

    1. /* DataStructure 预定义常量和类型头文件 */
    2. #ifndef STATUS_H
    3. #define STATUS_H
    4. #define CHECK_NULL(pointer) if (!(pointer)) { \
    5. printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_PTR); \
    6. return NULL; \
    7. }
    8. #define CHECK_RET(ret) if (ret != RET_OK) { \
    9. printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ret); \
    10. return ret; \
    11. }
    12. #define CHECK_VALUE(value, ERR_CODE) if (value) { \
    13. printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
    14. return ERR_CODE; \
    15. }
    16. #define CHECK_FALSE(value, ERR_CODE) if (!(value)) { \
    17. printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
    18. return FALSE; \
    19. }
    20. /* 函数结果状态码 */
    21. #define TRUE 1 /* 返回值为真 */
    22. #define FALSE 0 /* 返回值为假 */
    23. #define RET_OK 0 /* 返回值正确 */
    24. #define INFEASIABLE 2 /* 返回值未知 */
    25. #define ERR_MEMORY 3 /* 访问内存错 */
    26. #define ERR_NULL_PTR 4 /* 空指针错误 */
    27. #define ERR_MEMORY_ALLOCATE 5 /* 内存分配错 */
    28. #define ERR_NULL_STACK 6 /* 栈元素为空 */
    29. #define ERR_PARA 7 /* 函数参数错 */
    30. #define ERR_OPEN_FILE 8 /* 打开文件错 */
    31. #define ERR_NULL_QUEUE 9 /* 队列为空错 */
    32. #define ERR_FULL_QUEUE 10 /* 队列为满错 */
    33. #define ERR_NOT_FOUND 11 /* 表项不存在 */
    34. typedef int Status; /* Status 是函数的类型,其值是函数结果状态代码,如 RET_OK 等 */
    35. typedef int Bollean; /* Boolean 是布尔类型,其值是 TRUE 或 FALSE */
    36. #endif // !STATUS_H

    2) hString.h

    1. /* 串的堆分配存储实现头文件 */
    2. #ifndef HSTRING_H
    3. #define HSTRING_H
    4. #include "status.h"
    5. typedef struct {
    6. char *ch;
    7. int length;
    8. } HString;
    9. /* 初始化(产生空串)字符串 T */
    10. void InitString(HString *T);
    11. /* 生成一个其值等于串常量 chars 的串 T */
    12. Status StrAssign(const char *chars, HString *T);
    13. /* 初始条件: 串 S 存在
    14. 操作结果: 由串 S 复制得串 T */
    15. Status StrCopy(const HString *S, HString *T);
    16. /* 初始条件: 串 S 存在
    17. 操作结果: 若 S 为空串,则返回 TRUE,否则返回 FALSE */
    18. Bollean StrEmpty(const HString *S);
    19. /* 若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T,则返回值 < 0 */
    20. int StrCompare(const HString *S, const HString *T);
    21. /* 返回 S 的元素个数,称为串的长度 */
    22. int StrLength(const HString *S);
    23. /* 将 S 清为空串 */
    24. Status ClearString(HString *S);
    25. /* 用 T 返回由 S1 和 S2 联接而成的新串 */
    26. Status Concat(const HString *S1, const HString *S2, HString *T);
    27. /* 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串
    28. 其中,1 ≤ pos ≤ StrLength(S) 且 0 ≤ len ≤ StrLength(S) - pos + 1 */
    29. Status SubString(const HString *S, int pos, int len, HString *Sub);
    30. /* 算法 4.1,T 为非空串。若主串 S 中第 pos 个字符之后存在与 T 相等的子串
    31. 则返回第一个这样的子串在 S 中的位置,否则返回 0 */
    32. int Index(const HString *S, const HString *T, int pos);
    33. /* 算法 4.4, 在串 S 的第 pos 个字符之前插入串 T, 1 ≤ pos ≤ StrLength(S) + 1 */
    34. Status StrInsert(const HString *T, int pos, HString *S);
    35. /* 从串 S 中删除第 pos 个字符起长度为 len 的子串 */
    36. Status StrDelete(int pos, int len, HString *S);
    37. /* 初始条件: 串 S, T 和 V 存在, T 是非空串(此函数与串的存储结构无关)
    38. 操作结果: 用 V 替换主串 S 中出现的所有与 T 相等的不重叠的子串 */
    39. Status Replace(const HString *T, const HString *V, HString *S);
    40. /* 堆分配类型的字符串无法销毁(结构体)*/
    41. void DestroyString(void);
    42. /* 输出 T 字符串 */
    43. void StrPrint(const HString *T);
    44. #endif // !HSTRING_H

    3) hString.c

    1. /* 串的堆分配存储实现源文件 */
    2. #include "hString.h"
    3. #include
    4. #include
    5. #include
    6. /* 初始化(产生空串)字符串 T */
    7. void InitString(HString *T)
    8. {
    9. T->length = 0;
    10. T->ch = NULL;
    11. }
    12. /* 生成一个其值等于串常量 chars 的串 T */
    13. Status StrAssign(const char *chars, HString *T)
    14. {
    15. CHECK_VALUE(!chars, ERR_NULL_PTR);
    16. if (T->ch) {
    17. free(T->ch);
    18. }
    19. int length = (int)strlen(chars);
    20. if (length == 0) {
    21. T->ch = NULL;
    22. T->length = 0;
    23. return RET_OK;
    24. }
    25. T->ch = (char *)malloc(sizeof(char) * length);
    26. CHECK_VALUE(!(T->ch), ERR_MEMORY_ALLOCATE);
    27. T->length = length;
    28. for (int i = 0; i < length; ++i) {
    29. T->ch[i] = chars[i];
    30. }
    31. return RET_OK;
    32. }
    33. /* 初始条件: 串 S 存在
    34. 操作结果: 由串 S 复制得串 T */
    35. Status StrCopy(const HString *S, HString *T)
    36. {
    37. CHECK_VALUE(!S || !T, ERR_NULL_PTR);
    38. if (T->ch) {
    39. free(T->ch);
    40. }
    41. T->ch = (char *)malloc(sizeof(char) * (S->length));
    42. CHECK_VALUE(!(T->ch), ERR_MEMORY_ALLOCATE);
    43. T->length = S->length;
    44. for (int i = 0; i < S->length; ++i) {
    45. T->ch[i] = S->ch[i];
    46. }
    47. return RET_OK;
    48. }
    49. /* 初始条件: 串 S 存在
    50. 操作结果: 若 S 为空串,则返回 TRUE,否则返回 FALSE */
    51. Bollean StrEmpty(const HString *S)
    52. {
    53. return ((S->length == 0) && (S->ch == NULL)) ? TRUE : FALSE;
    54. }
    55. /* 若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T,则返回值 < 0 */
    56. int StrCompare(const HString *S, const HString *T)
    57. {
    58. CHECK_VALUE(!S || !T, ERR_NULL_PTR);
    59. for (int i = 0; i < S->length && i < T->length; ++i) {
    60. if (S->ch[i] != T->ch[i]) {
    61. return S->ch[i] - T->ch[i];
    62. }
    63. }
    64. return S->length - T->length;
    65. }
    66. /* 返回 S 的元素个数,称为串的长度 */
    67. int StrLength(const HString *S)
    68. {
    69. return S->length;
    70. }
    71. /* 将 S 清为空串 */
    72. Status ClearString(HString *S)
    73. {
    74. if (S->ch) {
    75. free(S->ch);
    76. S->ch = NULL;
    77. }
    78. S->length = 0;
    79. return RET_OK;
    80. }
    81. /* 用 T 返回由 S1 和 S2 联接而成的新串 */
    82. Status Concat(const HString *S1, const HString *S2, HString *T)
    83. {
    84. CHECK_VALUE(!S1 || !S2 || !T, ERR_NULL_PTR);
    85. if (T->ch) {
    86. free(T->ch);
    87. }
    88. int length = S1->length + S2->length;
    89. T->ch = (char *)malloc(sizeof(char) * length);
    90. CHECK_VALUE(!(T->ch), ERR_MEMORY_ALLOCATE);
    91. for (int i = 0; i < S1->length; ++i) {
    92. T->ch[i] = S1->ch[i];
    93. }
    94. for (int i = 0; i < S2->length; ++i) {
    95. T->ch[S1->length + i] = S2->ch[i];
    96. }
    97. T->length = length;
    98. return RET_OK;
    99. }
    100. /* 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串
    101. 其中,1 ≤ pos ≤ StrLength(S) 且 0 ≤ len ≤ StrLength(S) - pos + 1 */
    102. Status SubString(const HString *S, int pos, int len, HString *Sub)
    103. {
    104. CHECK_VALUE(!S || !Sub, ERR_NULL_PTR);
    105. CHECK_VALUE((pos < 1) || (pos > S->length) || (len < 0) || (len > S->length - pos + 1), ERR_PARA);
    106. if (Sub->ch) {
    107. free(Sub->ch);
    108. }
    109. if (len == 0) {
    110. Sub->ch = NULL;
    111. Sub->length = 0;
    112. } else {
    113. Sub->ch = (char *)malloc(sizeof(char) * len);
    114. CHECK_VALUE(!(Sub->ch), ERR_MEMORY_ALLOCATE);
    115. for (int i = 0; i < len; ++i) {
    116. Sub->ch[i] = S->ch[pos - 1 + i];
    117. }
    118. Sub->length = len;
    119. }
    120. return RET_OK;
    121. }
    122. /* 算法 4.1,T 为非空串。若主串 S 中第 pos 个字符之后存在与 T 相等的子串
    123. 则返回第一个这样的子串在 S 中的位置,否则返回 0 */
    124. int Index(const HString *S, const HString *T, int pos)
    125. {
    126. int maxRange = StrLength(S) - StrLength(T) + 1;
    127. CHECK_VALUE((pos < 1) || (pos > maxRange), 0);
    128. HString sub;
    129. InitString(&sub);
    130. while (pos <= maxRange) {
    131. SubString(S, pos, StrLength(T), &sub);
    132. if (StrCompare(&sub, T) != 0) {
    133. ++pos;
    134. } else {
    135. return pos;
    136. }
    137. }
    138. return 0;
    139. }
    140. /* 算法 4.4, 在串 S 的第 pos 个字符之前插入串 T, 1 ≤ pos ≤ StrLength(S) + 1 */
    141. Status StrInsert(const HString *T, int pos, HString *S)
    142. {
    143. CHECK_VALUE(!T || !S, ERR_NULL_PTR);
    144. CHECK_VALUE((pos < 1) || (pos > S->length + 1), ERR_PARA);
    145. if (T->length == 0) {
    146. return RET_OK;
    147. }
    148. S->ch = (char *)realloc(S->ch, sizeof(char) * (unsigned int)(S->length + T->length));
    149. CHECK_VALUE(!(S->ch), ERR_MEMORY_ALLOCATE);
    150. for (int i = S->length - 1; i >= pos - 1; --i) {
    151. S->ch[i + T->length] = S->ch[i];
    152. }
    153. S->length += T->length;
    154. for (int i = 0; i < T->length; ++i) {
    155. S->ch[pos - 1 + i] = T->ch[i];
    156. }
    157. return RET_OK;
    158. }
    159. /* 从串 S 中删除第 pos 个字符起长度为 len 的子串 */
    160. Status StrDelete(int pos, int len, HString *S)
    161. {
    162. CHECK_VALUE(!S, ERR_NULL_PTR);
    163. CHECK_VALUE(pos - 1 + len > S->length, ERR_PARA);
    164. for (int i = pos - 1; i < S->length - len; ++i) {
    165. S->ch[i] = S->ch[i + len];
    166. }
    167. S->length -= len;
    168. S->ch = (char *)realloc(S->ch, sizeof(char) * S->length);
    169. return RET_OK;
    170. }
    171. /* 初始条件: 串 S, T 和 V 存在, T 是非空串(此函数与串的存储结构无关)
    172. 操作结果: 用 V 替换主串 S 中出现的所有与 T 相等的不重叠的子串 */
    173. Status Replace(const HString *T, const HString *V, HString *S)
    174. {
    175. CHECK_VALUE(!T || !V || !S, ERR_NULL_PTR);
    176. int pos = 1;
    177. do {
    178. pos = Index(S, T, pos);
    179. if (pos) {
    180. StrDelete(pos, StrLength(T), S);
    181. StrInsert(V, pos, S);
    182. pos += StrLength(V);
    183. }
    184. } while (pos);
    185. return RET_OK;
    186. }
    187. /* 堆分配类型的字符串无法销毁(结构体)*/
    188. void DestroyString(void)
    189. {
    190. printf("Do not need to destroy!\n");
    191. }
    192. /* 输出 T 字符串 */
    193. void StrPrint(const HString *T)
    194. {
    195. for (int i = 0; i < T->length; ++i) {
    196. putchar(T->ch[i]);
    197. }
    198. }

    4) main.c

    1. /* 入口程序源文件 */
    2. #include "hString.h"
    3. #include
    4. int main(void)
    5. {
    6. HString t, s, r;
    7. InitString(&t);
    8. InitString(&s);
    9. InitString(&r);
    10. char *p = "Good bye!", *q = "Good luck!";
    11. StrAssign(p, &t);
    12. printf("The length of t is %d, and t is %s, and t is: ", StrLength(&t),
    13. (StrEmpty(&t) == TRUE) ? "empty" : "not empty");
    14. StrPrint(&t);
    15. putchar('\n');
    16. StrAssign(q, &s);
    17. printf("The length of s is %d, and s is %s, and s is: ", StrLength(&s),
    18. (StrEmpty(&s) == TRUE) ? "empty" : "not empty");
    19. StrPrint(&s);
    20. putchar('\n');
    21. Status ret = StrCompare(&s, &t);
    22. char ch = (ret == 0) ? '=' : ((ret < 0) ? '<' : '>');
    23. printf("s %c t\n", ch);
    24. Concat(&s, &t, &r);
    25. printf("The conncection of s and t is: ");
    26. StrPrint(&r);
    27. putchar('\n');
    28. printf("Now s is: ");
    29. StrAssign("oo", &s);
    30. StrPrint(&s);
    31. putchar('\n');
    32. printf("Now t is: ");
    33. StrAssign("o", &t);
    34. StrPrint(&t);
    35. putchar('\n');
    36. Replace(&t, &s, &r);
    37. printf("After use s replace t, r is: ");
    38. StrPrint(&r);
    39. putchar('\n');
    40. ClearString(&s);
    41. printf("After clear s, the length of s is %d, and s is %s, and s is: ", StrLength(&s),
    42. (StrEmpty(&s) == TRUE) ? "empty" : "not empty");
    43. StrPrint(&s);
    44. putchar('\n');
    45. SubString(&r, 6, 4, &s);
    46. printf("s is the string of r from 6th and length is %d\n", s.length);
    47. StrPrint(&s);
    48. putchar('\n');
    49. StrCopy(&r, &t);
    50. printf("After copy string r into string t, t is: ");
    51. StrPrint(&t);
    52. putchar('\n');
    53. StrInsert(&s, 6, &t);
    54. printf("After insert s into the 6th character of t, t is: ");
    55. StrPrint(&t);
    56. putchar('\n');
    57. StrDelete(1, 5, &t);
    58. printf("After delete 5 characters of t from 1th character, t is: ");
    59. StrPrint(&t);
    60. putchar('\n');
    61. printf("The position of the 1th same string with s from 1th character of t is %d\n",
    62. Index(&t, &s, 1));
    63. printf("The position of the 1th same string with s from 2th character of t is %d\n",
    64. Index(&t, &s, 2));
    65. ClearString(&s);
    66. ClearString(&t);
    67. ClearString(&r);
    68. DestroyString();
    69. return 0;
    70. }

    3. 输出示例

  • 相关阅读:
    【后台技术】异步编程指北,问题和重点
    用动图详细讲解——栈
    深度学习自学笔记四:浅层神经网络(一)
    旅游资讯查询易语言代码
    1-丁基-3-甲基咪唑锚氢氧化物[bmim]OH;新型氢氧型N-十二烷基双核吗啉离子液体[Nbmd]OH离子液体
    算法必刷系列之栈、队列、哈希
    Spring Boot项目开发实战:手动编写一个starter实现日志埋点记录信息
    Github 2024-05-08 开源项目日报 Top10
    ue unreal 虚幻 invalid HTTP response code received 问题
    Scala的函数式编程与高阶函数,匿名函数,偏函数,函数的闭包、柯里化,抽象控制,懒加载等
  • 原文地址:https://blog.csdn.net/qq_40613544/article/details/132921013