1. 背景说明
该实现和链表的实现极为相似,只是将链接的内存拆分为具体的大小的块。
2. 示例代码
1). status.h
/* DataStructure 预定义常量和类型头文件 */
#ifndef STATUS_H
#define STATUS_H
#define CHECK_NULL(pointer) if (!(pointer)) { \
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_PTR); \
return NULL; \
}
#define CHECK_RET(ret) if (ret != RET_OK) { \
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ret); \
return ret; \
}
#define CHECK_VALUE(value, ERR_CODE) if (value) { \
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
return ERR_CODE; \
}
#define CHECK_FALSE(value, ERR_CODE) if (!(value)) { \
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
return FALSE; \
}
/* 函数结果状态码 */
#define TRUE 1 /* 返回值为真 */
#define FALSE 0 /* 返回值为假 */
#define RET_OK 0 /* 返回值正确 */
#define INFEASIABLE 2 /* 返回值未知 */
#define ERR_MEMORY 3 /* 访问内存错 */
#define ERR_NULL_PTR 4 /* 空指针错误 */
#define ERR_MEMORY_ALLOCATE 5 /* 内存分配错 */
#define ERR_NULL_STACK 6 /* 栈元素为空 */
#define ERR_PARA 7 /* 函数参数错 */
#define ERR_OPEN_FILE 8 /* 打开文件错 */
#define ERR_NULL_QUEUE 9 /* 队列为空错 */
#define ERR_FULL_QUEUE 10 /* 队列为满错 */
#define ERR_NOT_FOUND 11 /* 表项不存在 */
typedef int Status; /* Status 是函数的类型,其值是函数结果状态代码,如 RET_OK 等 */
typedef int Bollean; /* Boolean 是布尔类型,其值是 TRUE 或 FALSE */
#endif // !STATUS_H
2) lString.h
/* 串的块链存储实现头文件 */
#ifndef LSTRING_H
#define LSTRING_H
#include "status.h"
#define CHUNK_SIZE 4
#define BLANK '#'
typedef struct Chunk {
char str[CHUNK_SIZE];
struct Chunk *next;
} Chunk;
typedef struct {
Chunk *head, *tail;
int curLen; /* 字符个数 */
} LString;
/* 初始化(产生空串)字符串 T */
Status InitString(LString *T);
/* 生成一个其值等于 chars 的串 T (要求 chars 中不包含填补空余的字符)
成功返回 OK,否则返回 ERROR */
Status StrAssign(const char *chars, LString *T);
/* 初始条件: 串 S 存在
操作结果: 由串 S 复制得串 T(连填补空余的字符一块拷贝) */
Status StrCopy(const LString *S, LString *T);
/* 初始条件:串 S 存在
操作结果:若 S 为空串,则返回 TRUE,否则返回 FALSE */
Bollean StrEmpty(const LString *S);
/* 若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T, 则返回值 < 0 */
int StrCompare(const LString *S, const LString *T);
/* 返回 S 的元素个数,称为串的长度 */
int StrLength(const LString *S);
/* 初始条件: 串 S 存在
操作结果: 将 S 清为空串 */
Status ClearString(LString *S);
/* 用 T 返回由 S1 和 S2 联接而成的新串 */
Status Concat(const LString *S1, const LString *S2, LString *T);
/* 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串
其中, 1≤ pos ≤ StrLength(S) 且 0 ≤ len ≤ StrLength(S) - pos + 1 */
Status SubString(const LString *S, int pos, int len, LString *Sub);
/* T 为非空串。若主串 S 中第 pos 个字符之后存在与 T 相等的子串
则返回第一个这样的子串在 S 中的位置,否则返回 0 */
int Index(const LString *S, const LString *T, int pos);
/* 压缩串(清除块中不必要的填补空余的字符) */
Status Zip(LString *S);
/* 1 ≤ pos ≤ StrLength(S) + 1。在串 S 的第 pos 个字符之前插入串 T */
Status StrInsert(const LString *T, int pos, LString *S);
/* 从串 S 中删除第 pos 个字符起长度为 len 的子串 */
Status StrDelete(int pos, int len, LString *S);
/* 初始条件: 串 S, T 和 V 存在,T 是非空串(此函数与串的存储结构无关)
操作结果: 用 V 替换主串 S 中出现的所有与 T 相等的不重叠的子串 */
Status Replace(const LString *T, const LString *V, LString *S);
/* 输出字符串 T */
void StrPrint(const LString *T);
#endif // !LSTRING_H
3) lString.c
/* 串的块链存储实现源文件 */
#include "lString.h"
#include
#include
#include
/* 初始化(产生空串)字符串 T */
Status InitString(LString *T)
{
CHECK_VALUE(!T, ERR_NULL_PTR);
T->curLen = 0;
T->head = NULL;
T->tail = NULL;
return RET_OK;
}
/* 生成一个其值等于 chars 的串 T (要求 chars 中不包含填补空余的字符)
成功返回 OK,否则返回 ERROR */
Status StrAssign(const char *chars, LString *T)
{
CHECK_VALUE(!chars || !T, ERR_NULL_PTR);
int length = (int)strlen(chars);
CHECK_VALUE((length == 0) || strchr(chars, BLANK), ERR_PARA);
T->curLen = length;
int nodes = length / CHUNK_SIZE;
if (length % CHUNK_SIZE) {
nodes += 1;
}
Chunk *tail = NULL, *newNode = NULL;
for (int i = 0; i < nodes; ++i) {
newNode = (Chunk *)malloc(sizeof(Chunk));
CHECK_VALUE(!newNode, ERR_NULL_PTR);
if (i == 0) {
T->head = tail = newNode;
} else {
tail->next = newNode;
tail = newNode;
}
int j;
for (j = 0; (j < CHUNK_SIZE) && (*chars); ++j) {
*(tail->str + j) = *chars++;
}
if (!(*chars)) {
T->tail = tail;
tail->next = NULL;
while (j < CHUNK_SIZE) {
*(tail->str + j++) = BLANK;
}
}
}
return RET_OK;
}
/* 初始条件: 串 S 存在
操作结果: 由串 S 复制得串 T(连填补空余的字符一块拷贝) */
Status StrCopy(const LString *S, LString *T)
{
CHECK_VALUE(!S || !T, ERR_NULL_PTR);
Chunk *sHead = S->head, *newNode = NULL;
T->head = NULL;
while (sHead) {
newNode = (Chunk *)malloc(sizeof(Chunk));
CHECK_VALUE(!newNode, ERR_MEMORY_ALLOCATE);
newNode->next = NULL;
(void)memcpy_s(newNode, sizeof(Chunk), sHead, sizeof(Chunk));
if (T->head == NULL) {
T->head = T->tail = newNode;
} else {
T->tail->next = newNode;
T->tail = newNode;
}
sHead = sHead->next;
}
T->curLen = S->curLen;
return RET_OK;
}
/* 初始条件:串 S 存在
操作结果:若 S 为空串,则返回 TRUE,否则返回 FALSE */
Bollean StrEmpty(const LString *S)
{
CHECK_VALUE(!S, ERR_NULL_PTR);
return (S->curLen == 0) ? TRUE : FALSE;
}
static void GetNextCharPos(Chunk **node, int *order)
{
++(*order);
if (*order == CHUNK_SIZE) {
*node = (*node)->next;
*order = 0;
}
}
static void GetNextLegalCharPos(Chunk **node, int *order)
{
while (*((*node)->str + *order) == BLANK) {
GetNextCharPos(node, order);
}
}
/* 若 S > T,则返回值 > 0;若 S = T,则返回值 = 0;若 S < T, 则返回值 < 0 */
int StrCompare(const LString *S, const LString *T)
{
CHECK_VALUE(!S || !T, ERR_NULL_PTR);
Chunk *ps = S->head, *pt = T->head;
for (int i = 0, js = 0, jt = 0; (i < S->curLen) && (i < T->curLen); ++i) {
GetNextLegalCharPos(&ps, &js);
GetNextLegalCharPos(&pt, &jt);
if (*(ps->str + js) != *(pt->str + jt)) {
return *(ps->str + js) - *(pt->str + jt);
}
GetNextCharPos(&ps, &js);
GetNextCharPos(&pt, &jt);
}
return S->curLen - T->curLen;
}
/* 返回 S 的元素个数,称为串的长度 */
int StrLength(const LString *S)
{
CHECK_VALUE(!S, ERR_NULL_PTR);
return S->curLen;
}
/* 初始条件: 串 S 存在
操作结果: 将 S 清为空串 */
Status ClearString(LString *S)
{
CHECK_VALUE(!S, ERR_NULL_PTR);
Chunk *p = S->head, *q = NULL;
while (p) {
q = p->next;
free(p);
p = q;
}
S->head = S->tail = NULL;
S->curLen = 0;
return RET_OK;
}
/* 用 T 返回由 S1 和 S2 联接而成的新串 */
Status Concat(const LString *S1, const LString *S2, LString *T)
{
CHECK_VALUE(!S1 || !S2 || !T, ERR_NULL_PTR);
LString str1, str2;
InitString(&str1);
InitString(&str2);
StrCopy(S1, &str1);
StrCopy(S2, &str2);
T->head = str1.head;
str1.tail->next = str2.head;
T->tail = str2.tail;
T->curLen = str1.curLen + str2.curLen;
return RET_OK;
}
/* 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串
其中, 1≤ pos ≤ StrLength(S) 且 0 ≤ len ≤ StrLength(S) - pos + 1 */
Status SubString(const LString *S, int pos, int len, LString *Sub)
{
CHECK_VALUE(!S || !Sub, ERR_NULL_PTR);
CHECK_VALUE((pos < 1) || (pos > S->curLen) || (len < 0) || (len > (S->curLen - pos + 1)), ERR_PARA);
int subLength = len / CHUNK_SIZE;
if (len % CHUNK_SIZE) {
subLength += 1;
}
Chunk *newNode = (Chunk *)malloc(sizeof(Chunk));
Sub->head = newNode;
Chunk *tail = Sub->head;
for (int i = 0; i < subLength - 1; ++i) {
newNode = (Chunk *)malloc(sizeof(Chunk));
tail->next = newNode;
tail = newNode;
}
tail->next = NULL;
Sub->tail = tail;
Sub->curLen = len;
int lastPos = len % CHUNK_SIZE;
if (lastPos) {
for (int i = lastPos; i < CHUNK_SIZE; ++i) {
*(newNode->str + i) = BLANK;
}
}
Chunk *subHead = Sub->head, *sHead = S->head;
int subPos = 0, count = 0;
Bollean isEnd = FALSE;
while (!isEnd) {
for (int i = 0; i < CHUNK_SIZE; ++i) {
if (*(sHead->str + i) == BLANK) {
continue;
}
++count;
if ((count >= pos) && (count <= pos + len - 1)) {
if (subPos == CHUNK_SIZE) {
subHead = subHead->next;
subPos = 0;
}
*(subHead->str + subPos) = *(sHead->str + i);
++subPos;
if (count == pos + len - 1) {
isEnd = TRUE;
break;
}
}
}
sHead = sHead->next;
}
return RET_OK;
}
/* T 为非空串。若主串 S 中第 pos 个字符之后存在与 T 相等的子串
则返回第一个这样的子串在 S 中的位置,否则返回 0 */
int Index(const LString *S, const LString *T, int pos)
{
CHECK_VALUE(!S || !T, ERR_NULL_PTR);
int maxRange = StrLength(S) - StrLength(T) + 1;
CHECK_VALUE((pos < 1) || (pos > maxRange), 0);
LString sub;
InitString(&sub);
while (pos <= maxRange) {
SubString(S, pos, StrLength(T), &sub);
if (StrCompare(T, &sub) == 0) {
return pos;
}
++pos;
}
return 0;
}
/* 压缩串(清除块中不必要的填补空余的字符) */
Status Zip(LString *S)
{
CHECK_VALUE(!S, ERR_NULL_PTR);
char *newStr = (char *)malloc(sizeof(char) * (unsigned int)(S->curLen + 1));
CHECK_VALUE(!newStr, ERR_NULL_PTR);
Chunk *sHead = S->head;
int count = 0;
while (sHead) {
for (int i = 0; i < CHUNK_SIZE; ++i) {
if (*(sHead->str + i) != BLANK) {
*(newStr + count) = *(sHead->str + i);
++count;
}
}
sHead = sHead->next;
}
*(newStr + count) = '\0';
ClearString(S);
StrAssign(newStr, S);
return RET_OK;
}
/* 1 ≤ pos ≤ StrLength(S) + 1。在串 S 的第 pos 个字符之前插入串 T */
Status StrInsert(const LString *T, int pos, LString *S)
{
CHECK_VALUE(!T || !S, ERR_MEMORY_ALLOCATE);
CHECK_VALUE((pos < 1) || (pos > StrLength(S) + 1), ERR_PARA);
LString t;
StrCopy(T, &t);
Zip(S);
int moveBlock = (pos - 1) / CHUNK_SIZE;
int insertPos = (pos - 1) % CHUNK_SIZE;
Chunk *sHead = S->head;
if (pos == 1) {
t.tail->next = S->head;
S->head = t.head;
} else if (insertPos == 0) {
for (int i = 0; i < moveBlock - 1; ++i) {
sHead = sHead->next;
}
Chunk *insertNext = sHead->next;
sHead->next = t.head;
t.tail->next = insertNext;
if (insertNext == NULL) {
S->tail = t.tail;
}
} else {
for (int i = 0; i < moveBlock; ++i) {
sHead = sHead->next;
}
Chunk *newBlock = (Chunk *)malloc(sizeof(Chunk));
CHECK_VALUE(!newBlock, ERR_NULL_PTR);
for (int i = 0; i < insertPos; ++i) {
*(newBlock->str + i) = BLANK;
}
for (int i = insertPos; i < CHUNK_SIZE; ++i) {
*(newBlock->str + i) = *(sHead->str + i);
*(sHead->str + i) = BLANK;
}
newBlock->next = sHead->next;
sHead->next = t.head;
t.tail->next = newBlock;
}
S->curLen += t.curLen;
Zip(S);
return RET_OK;
}
/* 从串 S 中删除第 pos 个字符起长度为 len 的子串 */
Status StrDelete(int pos, int len, LString *S)
{
CHECK_VALUE(!S, ERR_NULL_PTR);
CHECK_VALUE((pos < 1) || (pos > S->curLen - len + 1) || (len < 0), ERR_PARA);
int count = 0;
int currOrder = 0;
Chunk *sHead = S->head;
while (count < pos - 1) {
GetNextLegalCharPos(&sHead, &currOrder);
++count;
GetNextCharPos(&sHead, &currOrder);
}
++count;
if (*(sHead->str + currOrder) == BLANK) {
GetNextLegalCharPos(&sHead, &currOrder);
}
while (count < pos + len) {
GetNextLegalCharPos(&sHead, &currOrder);
*(sHead->str + currOrder) = BLANK;
++count;
GetNextCharPos(&sHead, &currOrder);
}
S->curLen -= len;
return RET_OK;
}
/* 初始条件: 串 S, T 和 V 存在,T 是非空串(此函数与串的存储结构无关)
操作结果: 用 V 替换主串 S 中出现的所有与 T 相等的不重叠的子串 */
Status Replace(const LString *T, const LString *V, LString *S)
{
CHECK_VALUE(!T || !V || !S, ERR_NULL_PTR);
CHECK_VALUE(StrEmpty(T), ERR_PARA);
int pos = 1;
do {
pos = Index(S, T, pos);
if (pos) {
StrDelete(pos, StrLength(T), S);
StrInsert(V, pos, S);
pos += StrLength(V);
}
} while (pos);
return RET_OK;
}
/* 输出字符串 T */
void StrPrint(const LString *T)
{
int count = 0;
Chunk *tHead = T->head;
while (count < T->curLen) {
for (int i = 0; i < CHUNK_SIZE; ++i) {
if (*(tHead->str + i) != BLANK) {
printf("%c", *(tHead->str + i));
++count;
}
}
tHead = tHead->next;
}
}
4) main.c
/* 入口程序源文件 */
#include "lString.h"
#include
void ShowStr(const LString *S, const char *stringName);
int main(void)
{
LString t1, t2, t3, t4;
InitString(&t1);
InitString(&t2);
InitString(&t3);
InitString(&t4);
printf("After initialize the string t1, the string t1 is %s,"
"the length of string t1 is %d\n", (StrEmpty(&t1) == TRUE) ? "empty" : "not empty",
StrLength(&t1));
char *s1 = "ABCDEFGHI", *s2 = "12345", *s3 = "", *s4 = "asd#tr", *s5 = "ABCD";
Status ret = StrAssign(s3, &t1);
if (ret == RET_OK) {
ShowStr(&t1, "t1");
}
ret = StrAssign(s4, &t1);
if (ret == RET_OK) {
ShowStr(&t1, "t1");
}
ret = StrAssign(s1, &t1);
if (ret == RET_OK) {
ShowStr(&t1, "t1");
}
printf("After assign s1 to the string t1, the string t1 is %s,"
"the length of string t1 is %d\n", (StrEmpty(&t1) == TRUE) ? "empty" : "not empty",
StrLength(&t1));
ret = StrAssign(s2, &t2);
if (ret == RET_OK) {
ShowStr(&t2, "t2");
}
StrCopy(&t1, &t3);
ShowStr(&t3, "t3");
ret = StrAssign(s5, &t4);
if (ret == RET_OK) {
ShowStr(&t4, "t4");
}
Replace(&t4, &t2, &t3);
ShowStr(&t3, "t3");
ClearString(&t1);
printf("After clear string t1, the string t1 is %s,"
"the length of string t1 is %d\n", (StrEmpty(&t1) == TRUE) ? "empty" : "not empty",
StrLength(&t1));
Concat(&t2, &t3, &t1);
ShowStr(&t1, "t1");
Zip(&t1);
ShowStr(&t1, "t1");
int pos = Index(&t1, &t3, 1);
printf("pos = %d\n", pos);
printf("To insert the string t2 before the posTh character of the string t1, enter pos: ");
scanf_s("%d", &pos);
StrInsert(&t2, pos, &t1);
ShowStr(&t1, "t1");
int len;
printf("Please input the position and length of the subString of t1: ");
scanf_s("%d%d", &pos, &len);
ClearString(&t2);
SubString(&t1, pos, len, &t2);
ShowStr(&t2, "t2");
printf("StrCompare(&t1, &t2) = %d\n", StrCompare(&t1, &t2));
printf("Please input the position and length of the string t1 to be delete: ");
scanf_s("%d%d", &pos, &len);
StrDelete(pos, len, &t1);
ShowStr(&t1, "t1");
t1.head->str[0] = BLANK;
t1.curLen--;
printf("t1.head->str[0] = %c\n", t1.head->str[0]);
ShowStr(&t1, "t1");
Zip(&t1);
printf("t1.head->str[0] = %c\n", t1.head->str[0]);
ShowStr(&t1, "t1");
ClearString(&t1);
ClearString(&t2);
ClearString(&t3);
ClearString(&t4);
return 0;
}
void ShowStr(const LString *S, const char *stringName)
{
printf("The string %s is: ", stringName);
StrPrint(S);
printf("\n");
}
3. 运行示例