• 第 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) lString.h

    1. /* 串的块链存储实现头文件 */
    2. #ifndef LSTRING_H
    3. #define LSTRING_H
    4. #include "status.h"
    5. #define CHUNK_SIZE 4
    6. #define BLANK '#'
    7. typedef struct Chunk {
    8. char str[CHUNK_SIZE];
    9. struct Chunk *next;
    10. } Chunk;
    11. typedef struct {
    12. Chunk *head, *tail;
    13. int curLen; /* 字符个数 */
    14. } LString;
    15. /* 初始化(产生空串)字符串 T */
    16. Status InitString(LString *T);
    17. /* 生成一个其值等于 chars 的串 T (要求 chars 中不包含填补空余的字符)
    18. 成功返回 OK,否则返回 ERROR */
    19. Status StrAssign(const char *chars, LString *T);
    20. /* 初始条件: 串 S 存在
    21. 操作结果: 由串 S 复制得串 T(连填补空余的字符一块拷贝) */
    22. Status StrCopy(const LString *S, LString *T);
    23. /* 初始条件:串 S 存在
    24. 操作结果:若 S 为空串,则返回 TRUE,否则返回 FALSE */
    25. Bollean StrEmpty(const LString *S);
    26. /* 若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T, 则返回值 < 0 */
    27. int StrCompare(const LString *S, const LString *T);
    28. /* 返回 S 的元素个数,称为串的长度 */
    29. int StrLength(const LString *S);
    30. /* 初始条件: 串 S 存在
    31. 操作结果: 将 S 清为空串 */
    32. Status ClearString(LString *S);
    33. /* 用 T 返回由 S1 和 S2 联接而成的新串 */
    34. Status Concat(const LString *S1, const LString *S2, LString *T);
    35. /* 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串
    36. 其中, 1≤ pos ≤ StrLength(S) 且 0 ≤ len ≤ StrLength(S) - pos + 1 */
    37. Status SubString(const LString *S, int pos, int len, LString *Sub);
    38. /* T 为非空串。若主串 S 中第 pos 个字符之后存在与 T 相等的子串
    39. 则返回第一个这样的子串在 S 中的位置,否则返回 0 */
    40. int Index(const LString *S, const LString *T, int pos);
    41. /* 压缩串(清除块中不必要的填补空余的字符) */
    42. Status Zip(LString *S);
    43. /* 1 ≤ pos ≤ StrLength(S) + 1。在串 S 的第 pos 个字符之前插入串 T */
    44. Status StrInsert(const LString *T, int pos, LString *S);
    45. /* 从串 S 中删除第 pos 个字符起长度为 len 的子串 */
    46. Status StrDelete(int pos, int len, LString *S);
    47. /* 初始条件: 串 S, T 和 V 存在,T 是非空串(此函数与串的存储结构无关)
    48. 操作结果: 用 V 替换主串 S 中出现的所有与 T 相等的不重叠的子串 */
    49. Status Replace(const LString *T, const LString *V, LString *S);
    50. /* 输出字符串 T */
    51. void StrPrint(const LString *T);
    52. #endif // !LSTRING_H

    3) lString.c

    1. /* 串的块链存储实现源文件 */
    2. #include "lString.h"
    3. #include
    4. #include
    5. #include
    6. /* 初始化(产生空串)字符串 T */
    7. Status InitString(LString *T)
    8. {
    9. CHECK_VALUE(!T, ERR_NULL_PTR);
    10. T->curLen = 0;
    11. T->head = NULL;
    12. T->tail = NULL;
    13. return RET_OK;
    14. }
    15. /* 生成一个其值等于 chars 的串 T (要求 chars 中不包含填补空余的字符)
    16. 成功返回 OK,否则返回 ERROR */
    17. Status StrAssign(const char *chars, LString *T)
    18. {
    19. CHECK_VALUE(!chars || !T, ERR_NULL_PTR);
    20. int length = (int)strlen(chars);
    21. CHECK_VALUE((length == 0) || strchr(chars, BLANK), ERR_PARA);
    22. T->curLen = length;
    23. int nodes = length / CHUNK_SIZE;
    24. if (length % CHUNK_SIZE) {
    25. nodes += 1;
    26. }
    27. Chunk *tail = NULL, *newNode = NULL;
    28. for (int i = 0; i < nodes; ++i) {
    29. newNode = (Chunk *)malloc(sizeof(Chunk));
    30. CHECK_VALUE(!newNode, ERR_NULL_PTR);
    31. if (i == 0) {
    32. T->head = tail = newNode;
    33. } else {
    34. tail->next = newNode;
    35. tail = newNode;
    36. }
    37. int j;
    38. for (j = 0; (j < CHUNK_SIZE) && (*chars); ++j) {
    39. *(tail->str + j) = *chars++;
    40. }
    41. if (!(*chars)) {
    42. T->tail = tail;
    43. tail->next = NULL;
    44. while (j < CHUNK_SIZE) {
    45. *(tail->str + j++) = BLANK;
    46. }
    47. }
    48. }
    49. return RET_OK;
    50. }
    51. /* 初始条件: 串 S 存在
    52. 操作结果: 由串 S 复制得串 T(连填补空余的字符一块拷贝) */
    53. Status StrCopy(const LString *S, LString *T)
    54. {
    55. CHECK_VALUE(!S || !T, ERR_NULL_PTR);
    56. Chunk *sHead = S->head, *newNode = NULL;
    57. T->head = NULL;
    58. while (sHead) {
    59. newNode = (Chunk *)malloc(sizeof(Chunk));
    60. CHECK_VALUE(!newNode, ERR_MEMORY_ALLOCATE);
    61. newNode->next = NULL;
    62. (void)memcpy_s(newNode, sizeof(Chunk), sHead, sizeof(Chunk));
    63. if (T->head == NULL) {
    64. T->head = T->tail = newNode;
    65. } else {
    66. T->tail->next = newNode;
    67. T->tail = newNode;
    68. }
    69. sHead = sHead->next;
    70. }
    71. T->curLen = S->curLen;
    72. return RET_OK;
    73. }
    74. /* 初始条件:串 S 存在
    75. 操作结果:若 S 为空串,则返回 TRUE,否则返回 FALSE */
    76. Bollean StrEmpty(const LString *S)
    77. {
    78. CHECK_VALUE(!S, ERR_NULL_PTR);
    79. return (S->curLen == 0) ? TRUE : FALSE;
    80. }
    81. static void GetNextCharPos(Chunk **node, int *order)
    82. {
    83. ++(*order);
    84. if (*order == CHUNK_SIZE) {
    85. *node = (*node)->next;
    86. *order = 0;
    87. }
    88. }
    89. static void GetNextLegalCharPos(Chunk **node, int *order)
    90. {
    91. while (*((*node)->str + *order) == BLANK) {
    92. GetNextCharPos(node, order);
    93. }
    94. }
    95. /* 若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T, 则返回值 < 0 */
    96. int StrCompare(const LString *S, const LString *T)
    97. {
    98. CHECK_VALUE(!S || !T, ERR_NULL_PTR);
    99. Chunk *ps = S->head, *pt = T->head;
    100. for (int i = 0, js = 0, jt = 0; (i < S->curLen) && (i < T->curLen); ++i) {
    101. GetNextLegalCharPos(&ps, &js);
    102. GetNextLegalCharPos(&pt, &jt);
    103. if (*(ps->str + js) != *(pt->str + jt)) {
    104. return *(ps->str + js) - *(pt->str + jt);
    105. }
    106. GetNextCharPos(&ps, &js);
    107. GetNextCharPos(&pt, &jt);
    108. }
    109. return S->curLen - T->curLen;
    110. }
    111. /* 返回 S 的元素个数,称为串的长度 */
    112. int StrLength(const LString *S)
    113. {
    114. CHECK_VALUE(!S, ERR_NULL_PTR);
    115. return S->curLen;
    116. }
    117. /* 初始条件: 串 S 存在
    118. 操作结果: 将 S 清为空串 */
    119. Status ClearString(LString *S)
    120. {
    121. CHECK_VALUE(!S, ERR_NULL_PTR);
    122. Chunk *p = S->head, *q = NULL;
    123. while (p) {
    124. q = p->next;
    125. free(p);
    126. p = q;
    127. }
    128. S->head = S->tail = NULL;
    129. S->curLen = 0;
    130. return RET_OK;
    131. }
    132. /* 用 T 返回由 S1 和 S2 联接而成的新串 */
    133. Status Concat(const LString *S1, const LString *S2, LString *T)
    134. {
    135. CHECK_VALUE(!S1 || !S2 || !T, ERR_NULL_PTR);
    136. LString str1, str2;
    137. InitString(&str1);
    138. InitString(&str2);
    139. StrCopy(S1, &str1);
    140. StrCopy(S2, &str2);
    141. T->head = str1.head;
    142. str1.tail->next = str2.head;
    143. T->tail = str2.tail;
    144. T->curLen = str1.curLen + str2.curLen;
    145. return RET_OK;
    146. }
    147. /* 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串
    148. 其中, 1≤ pos ≤ StrLength(S) 且 0 ≤ len ≤ StrLength(S) - pos + 1 */
    149. Status SubString(const LString *S, int pos, int len, LString *Sub)
    150. {
    151. CHECK_VALUE(!S || !Sub, ERR_NULL_PTR);
    152. CHECK_VALUE((pos < 1) || (pos > S->curLen) || (len < 0) || (len > (S->curLen - pos + 1)), ERR_PARA);
    153. int subLength = len / CHUNK_SIZE;
    154. if (len % CHUNK_SIZE) {
    155. subLength += 1;
    156. }
    157. Chunk *newNode = (Chunk *)malloc(sizeof(Chunk));
    158. Sub->head = newNode;
    159. Chunk *tail = Sub->head;
    160. for (int i = 0; i < subLength - 1; ++i) {
    161. newNode = (Chunk *)malloc(sizeof(Chunk));
    162. tail->next = newNode;
    163. tail = newNode;
    164. }
    165. tail->next = NULL;
    166. Sub->tail = tail;
    167. Sub->curLen = len;
    168. int lastPos = len % CHUNK_SIZE;
    169. if (lastPos) {
    170. for (int i = lastPos; i < CHUNK_SIZE; ++i) {
    171. *(newNode->str + i) = BLANK;
    172. }
    173. }
    174. Chunk *subHead = Sub->head, *sHead = S->head;
    175. int subPos = 0, count = 0;
    176. Bollean isEnd = FALSE;
    177. while (!isEnd) {
    178. for (int i = 0; i < CHUNK_SIZE; ++i) {
    179. if (*(sHead->str + i) == BLANK) {
    180. continue;
    181. }
    182. ++count;
    183. if ((count >= pos) && (count <= pos + len - 1)) {
    184. if (subPos == CHUNK_SIZE) {
    185. subHead = subHead->next;
    186. subPos = 0;
    187. }
    188. *(subHead->str + subPos) = *(sHead->str + i);
    189. ++subPos;
    190. if (count == pos + len - 1) {
    191. isEnd = TRUE;
    192. break;
    193. }
    194. }
    195. }
    196. sHead = sHead->next;
    197. }
    198. return RET_OK;
    199. }
    200. /* T 为非空串。若主串 S 中第 pos 个字符之后存在与 T 相等的子串
    201. 则返回第一个这样的子串在 S 中的位置,否则返回 0 */
    202. int Index(const LString *S, const LString *T, int pos)
    203. {
    204. CHECK_VALUE(!S || !T, ERR_NULL_PTR);
    205. int maxRange = StrLength(S) - StrLength(T) + 1;
    206. CHECK_VALUE((pos < 1) || (pos > maxRange), 0);
    207. LString sub;
    208. InitString(&sub);
    209. while (pos <= maxRange) {
    210. SubString(S, pos, StrLength(T), &sub);
    211. if (StrCompare(T, &sub) == 0) {
    212. return pos;
    213. }
    214. ++pos;
    215. }
    216. return 0;
    217. }
    218. /* 压缩串(清除块中不必要的填补空余的字符) */
    219. Status Zip(LString *S)
    220. {
    221. CHECK_VALUE(!S, ERR_NULL_PTR);
    222. char *newStr = (char *)malloc(sizeof(char) * (unsigned int)(S->curLen + 1));
    223. CHECK_VALUE(!newStr, ERR_NULL_PTR);
    224. Chunk *sHead = S->head;
    225. int count = 0;
    226. while (sHead) {
    227. for (int i = 0; i < CHUNK_SIZE; ++i) {
    228. if (*(sHead->str + i) != BLANK) {
    229. *(newStr + count) = *(sHead->str + i);
    230. ++count;
    231. }
    232. }
    233. sHead = sHead->next;
    234. }
    235. *(newStr + count) = '\0';
    236. ClearString(S);
    237. StrAssign(newStr, S);
    238. return RET_OK;
    239. }
    240. /* 1 ≤ pos ≤ StrLength(S) + 1。在串 S 的第 pos 个字符之前插入串 T */
    241. Status StrInsert(const LString *T, int pos, LString *S)
    242. {
    243. CHECK_VALUE(!T || !S, ERR_MEMORY_ALLOCATE);
    244. CHECK_VALUE((pos < 1) || (pos > StrLength(S) + 1), ERR_PARA);
    245. LString t;
    246. StrCopy(T, &t);
    247. Zip(S);
    248. int moveBlock = (pos - 1) / CHUNK_SIZE;
    249. int insertPos = (pos - 1) % CHUNK_SIZE;
    250. Chunk *sHead = S->head;
    251. if (pos == 1) {
    252. t.tail->next = S->head;
    253. S->head = t.head;
    254. } else if (insertPos == 0) {
    255. for (int i = 0; i < moveBlock - 1; ++i) {
    256. sHead = sHead->next;
    257. }
    258. Chunk *insertNext = sHead->next;
    259. sHead->next = t.head;
    260. t.tail->next = insertNext;
    261. if (insertNext == NULL) {
    262. S->tail = t.tail;
    263. }
    264. } else {
    265. for (int i = 0; i < moveBlock; ++i) {
    266. sHead = sHead->next;
    267. }
    268. Chunk *newBlock = (Chunk *)malloc(sizeof(Chunk));
    269. CHECK_VALUE(!newBlock, ERR_NULL_PTR);
    270. for (int i = 0; i < insertPos; ++i) {
    271. *(newBlock->str + i) = BLANK;
    272. }
    273. for (int i = insertPos; i < CHUNK_SIZE; ++i) {
    274. *(newBlock->str + i) = *(sHead->str + i);
    275. *(sHead->str + i) = BLANK;
    276. }
    277. newBlock->next = sHead->next;
    278. sHead->next = t.head;
    279. t.tail->next = newBlock;
    280. }
    281. S->curLen += t.curLen;
    282. Zip(S);
    283. return RET_OK;
    284. }
    285. /* 从串 S 中删除第 pos 个字符起长度为 len 的子串 */
    286. Status StrDelete(int pos, int len, LString *S)
    287. {
    288. CHECK_VALUE(!S, ERR_NULL_PTR);
    289. CHECK_VALUE((pos < 1) || (pos > S->curLen - len + 1) || (len < 0), ERR_PARA);
    290. int count = 0;
    291. int currOrder = 0;
    292. Chunk *sHead = S->head;
    293. while (count < pos - 1) {
    294. GetNextLegalCharPos(&sHead, &currOrder);
    295. ++count;
    296. GetNextCharPos(&sHead, &currOrder);
    297. }
    298. ++count;
    299. if (*(sHead->str + currOrder) == BLANK) {
    300. GetNextLegalCharPos(&sHead, &currOrder);
    301. }
    302. while (count < pos + len) {
    303. GetNextLegalCharPos(&sHead, &currOrder);
    304. *(sHead->str + currOrder) = BLANK;
    305. ++count;
    306. GetNextCharPos(&sHead, &currOrder);
    307. }
    308. S->curLen -= len;
    309. return RET_OK;
    310. }
    311. /* 初始条件: 串 S, T 和 V 存在,T 是非空串(此函数与串的存储结构无关)
    312. 操作结果: 用 V 替换主串 S 中出现的所有与 T 相等的不重叠的子串 */
    313. Status Replace(const LString *T, const LString *V, LString *S)
    314. {
    315. CHECK_VALUE(!T || !V || !S, ERR_NULL_PTR);
    316. CHECK_VALUE(StrEmpty(T), ERR_PARA);
    317. int pos = 1;
    318. do {
    319. pos = Index(S, T, pos);
    320. if (pos) {
    321. StrDelete(pos, StrLength(T), S);
    322. StrInsert(V, pos, S);
    323. pos += StrLength(V);
    324. }
    325. } while (pos);
    326. return RET_OK;
    327. }
    328. /* 输出字符串 T */
    329. void StrPrint(const LString *T)
    330. {
    331. int count = 0;
    332. Chunk *tHead = T->head;
    333. while (count < T->curLen) {
    334. for (int i = 0; i < CHUNK_SIZE; ++i) {
    335. if (*(tHead->str + i) != BLANK) {
    336. printf("%c", *(tHead->str + i));
    337. ++count;
    338. }
    339. }
    340. tHead = tHead->next;
    341. }
    342. }

    4) main.c

    1. /* 入口程序源文件 */
    2. #include "lString.h"
    3. #include
    4. void ShowStr(const LString *S, const char *stringName);
    5. int main(void)
    6. {
    7. LString t1, t2, t3, t4;
    8. InitString(&t1);
    9. InitString(&t2);
    10. InitString(&t3);
    11. InitString(&t4);
    12. printf("After initialize the string t1, the string t1 is %s,"
    13. "the length of string t1 is %d\n", (StrEmpty(&t1) == TRUE) ? "empty" : "not empty",
    14. StrLength(&t1));
    15. char *s1 = "ABCDEFGHI", *s2 = "12345", *s3 = "", *s4 = "asd#tr", *s5 = "ABCD";
    16. Status ret = StrAssign(s3, &t1);
    17. if (ret == RET_OK) {
    18. ShowStr(&t1, "t1");
    19. }
    20. ret = StrAssign(s4, &t1);
    21. if (ret == RET_OK) {
    22. ShowStr(&t1, "t1");
    23. }
    24. ret = StrAssign(s1, &t1);
    25. if (ret == RET_OK) {
    26. ShowStr(&t1, "t1");
    27. }
    28. printf("After assign s1 to the string t1, the string t1 is %s,"
    29. "the length of string t1 is %d\n", (StrEmpty(&t1) == TRUE) ? "empty" : "not empty",
    30. StrLength(&t1));
    31. ret = StrAssign(s2, &t2);
    32. if (ret == RET_OK) {
    33. ShowStr(&t2, "t2");
    34. }
    35. StrCopy(&t1, &t3);
    36. ShowStr(&t3, "t3");
    37. ret = StrAssign(s5, &t4);
    38. if (ret == RET_OK) {
    39. ShowStr(&t4, "t4");
    40. }
    41. Replace(&t4, &t2, &t3);
    42. ShowStr(&t3, "t3");
    43. ClearString(&t1);
    44. printf("After clear string t1, the string t1 is %s,"
    45. "the length of string t1 is %d\n", (StrEmpty(&t1) == TRUE) ? "empty" : "not empty",
    46. StrLength(&t1));
    47. Concat(&t2, &t3, &t1);
    48. ShowStr(&t1, "t1");
    49. Zip(&t1);
    50. ShowStr(&t1, "t1");
    51. int pos = Index(&t1, &t3, 1);
    52. printf("pos = %d\n", pos);
    53. printf("To insert the string t2 before the posTh character of the string t1, enter pos: ");
    54. scanf_s("%d", &pos);
    55. StrInsert(&t2, pos, &t1);
    56. ShowStr(&t1, "t1");
    57. int len;
    58. printf("Please input the position and length of the subString of t1: ");
    59. scanf_s("%d%d", &pos, &len);
    60. ClearString(&t2);
    61. SubString(&t1, pos, len, &t2);
    62. ShowStr(&t2, "t2");
    63. printf("StrCompare(&t1, &t2) = %d\n", StrCompare(&t1, &t2));
    64. printf("Please input the position and length of the string t1 to be delete: ");
    65. scanf_s("%d%d", &pos, &len);
    66. StrDelete(pos, len, &t1);
    67. ShowStr(&t1, "t1");
    68. t1.head->str[0] = BLANK;
    69. t1.curLen--;
    70. printf("t1.head->str[0] = %c\n", t1.head->str[0]);
    71. ShowStr(&t1, "t1");
    72. Zip(&t1);
    73. printf("t1.head->str[0] = %c\n", t1.head->str[0]);
    74. ShowStr(&t1, "t1");
    75. ClearString(&t1);
    76. ClearString(&t2);
    77. ClearString(&t3);
    78. ClearString(&t4);
    79. return 0;
    80. }
    81. void ShowStr(const LString *S, const char *stringName)
    82. {
    83. printf("The string %s is: ", stringName);
    84. StrPrint(S);
    85. printf("\n");
    86. }

    3. 运行示例

  • 相关阅读:
    React v6(仅支持函数组件,不支持类组件)与v5版本路由使用详情和区别(详细版)
    [附源码]Python计算机毕业设计Django居家养老服务系统小程序
    【100天精通Python】Day72:Python可视化_一文掌握Seaborn库的使用《二》_分类数据可视化,线性模型和参数拟合的可视化,示例+代码
    <HarmonyOS第一课>ArkTS开发语言介绍——闯关习题及答案
    vuejs - - - - - 递归组件的实现
    C++Qt开发——音视频播放
    开发过程中常见数据库。
    Geoserver的WFS服务实现要素的增删改
    Java基础- 浅谈javac和javap
    java毕业设计电子病历系统mybatis+源码+调试部署+系统+数据库+lw
  • 原文地址:https://blog.csdn.net/qq_40613544/article/details/133103566