一、实验要求
顺序串上的插入和删除操作不方便,需要移动大量的字符。因此,我们可用单链表方式来存储串值。这种存储方式适用于需要进行大量的字符串插入删除操作的场景。
构建一个链串,要求至少能完成如下操作:
赋值、比较、求串长、联接、取子串、插入(前插、后插)、删除、清除。
二、参考代码
为了锻炼阅读代码的能力,本文的全部代码都不作详细注释。如果难以看懂,可以在草稿纸上模拟代码的执行过程再进行理解。
代码及其简要注释:
1、malloc 分配的变量不会被初始化,且 malloc 不会调用构造函数来给变量赋值。因此在 malloc 分配了变量后,如果需要给一个默认值,必须手动调用相应的构造函数。如果是直接声明变量或用 new 分配变量地址,那么构造函数会被自动调用。构造函数不返回任何值,也不需要写 void 。
2、部分函数要求传入区间 [l, r] 作为参数,且会自动检测是否 l > r 。如果是,交换两个端点。
3、有的函数会返回 bool 类型,true 和 false 代表操作成功和操作失败(操作未执行)。
4、lstrcmp 函数返回正值代表串 s(第一个字符串)比 t(第二个字符串)的字典序大,返回负数代表 s 比 t 的字典序小,返回 0 代表 s 和 t 相等。
5、将串写成类似链表的形式是针对大量插入删除操作的场景的,这种方式的存储空间利用率很低。读者可以尝试在每个节点同时存储多个字符来减小存储空间的占用。
6、代码仅供参考。随着运行持续时间的增加,从 Visual Studio 中发现内存占用一直在增长。我并没有在代码中发现内存泄漏,为何内存占用会越来越多,原因暂时不明。
7、本链式串中每个串的结尾会留一个空节点,储存字符为 0 ,下一个节点的指针为 nullptr 。
#include<cstdio>
#include<algorithm>
#include<random>
#include<cstring>
#include<ctime>
typedef unsigned long long ull;
#pragma warning(disable:4996)
struct schar {
char c = 0; schar* next = nullptr;
schar(schar* p);
};
struct lstring {
schar* string = nullptr; ull len = 0;
lstring();
lstring(lstring* p);
};
char str[1025]; lstring s, t, u, v; std::default_random_engine d; ull l, a, b; int cmpres;
std::uniform_int_distribution<short> c(32, 126); std::uniform_int_distribution<ull> x(1, 128);
inline schar::schar(schar* p) {
p->c = 0, p->next = nullptr;
}
inline lstring::lstring() {
this->string = (schar*)malloc(sizeof(schar)), schar::schar(this->string);
}
inline lstring::lstring(lstring* p) {
p->string = (schar*)malloc(sizeof(schar)), schar::schar(p->string);
}
template<typename _Ty> inline _Ty randint(_Ty l, _Ty r) {
if (l > r)std::swap(l, r);
std::uniform_int_distribution<_Ty> u(l, r); return u(d);
}
inline void printlstr(const lstring& s) {
schar* p = s.string;
while (p->next != nullptr) { putchar(p->c), p = p->next; }
}
inline void clearlstr(lstring& s) {
if (s.string == nullptr)return;
schar* p = s.string, * q;
while (p->next != nullptr) { q = p, p = p->next, free(q); }
s.len = 0, s.string = p;
}
inline void lstrassign(lstring& s, const char* str) {
if (s.string->next != nullptr)clearlstr(s);
s.len = strlen(str); schar* p = s.string;
for (ull i = 0; i < s.len; ++i) { p->c = str[i], p->next = (schar*)malloc(sizeof(schar)), schar::schar(p->next), p = p->next; }
}
inline void lstrcpy(lstring& dest, const lstring& src) {
if (dest.string->next != nullptr)clearlstr(dest);
dest.len = src.len; schar* p = dest.string, * q = src.string;
for (ull i = 0; i < dest.len; ++i) { p->c = q->c, p->next = (schar*)malloc(sizeof(schar)), schar::schar(p->next), p = p->next, q = q->next; }
}
inline int lstrcmp(const lstring& s, const lstring& t) {
ull l = std::min(s.len, t.len); schar* p = s.string, * q = t.string;
for (ull i = 0; i < l; ++i) {
if ((*p).c != (*q).c)return (*p).c - (*q).c;
p = p->next, q = q->next;
}
return 0;
}
inline void lstrcat(lstring& dest, const lstring& s, const lstring& t) {
if (dest.string->next != nullptr)clearlstr(dest);
dest.len = s.len + t.len; schar* p = s.string, * r = dest.string;
for (ull i = 0; i < s.len; ++i) { r->c = p->c, r->next = (schar*)malloc(sizeof(schar)), schar::schar(r->next), r = r->next, p = p->next; }
p = t.string;
for (ull i = s.len; i < dest.len; ++i) { r->c = p->c, r->next = (schar*)malloc(sizeof(schar)), schar::schar(r->next), r = r->next, p = p->next; }
}
inline lstring sublstr(const lstring& s, ull l, ull r) {
if (l > r)std::swap(l, r);
if (l >= s.len)l = s.len - 1;
if (r >= s.len)r = s.len - 1;
lstring t; t.len = r - l + 1; schar* p = s.string, * q = t.string;
for (ull i = 0; i < l; ++i) { p = p->next; }
for (ull i = l; i <= r; ++i) { q->c = p->c, p = p->next, q->next = (schar*)malloc(sizeof(schar)), schar::schar(q->next), q = q->next; }
return t;
}
inline bool lstrins_front(lstring& dest, const char* str, ull off) {
ull l = strlen(str); if (l == 0)return false;
if (off >= dest.len)off = dest.len - 1;
ull l0 = l - 1, off0 = 0; schar* o, * p = dest.string, * q = (schar*)malloc(sizeof(schar)), * r = q; schar::schar(q);
if (off != 0)off0 = off - 1;
for (ull i = 0; i < off0; ++i) { p = p->next; }
o = p, p = p->next;
for (ull i = 0; i < l0; ++i) { q->c = str[i], q->next = (schar*)malloc(sizeof(schar)), schar::schar(q->next), q = q->next; }
q->c = str[l0], q->next = p, dest.len += l;
if (off == 0) { q->next = dest.string, dest.string = r; return true; }
o->next = r; return true;
}
inline bool lstrins_rear(lstring& dest, const char* str, ull off) {
ull l = strlen(str); if (l == 0)return false;
if (off >= dest.len)off = dest.len - 1;
ull l0 = l - 1; schar* o, * p = dest.string, * q = (schar*)malloc(sizeof(schar)), * r = q; schar::schar(q);
for (ull i = 0; i < off; ++i) { p = p->next; }
o = p, p = p->next;
for (ull i = 0; i < l0; ++i) { q->c = str[i], q->next = (schar*)malloc(sizeof(schar)), schar::schar(q->next), q = q->next; }
q->c = str[l0], q->next = p, dest.len += l;
o->next = r; return true;
}
inline bool lstrins_front(lstring& dest, const lstring& src, ull off) {
if (src.len == 0)return false;
if (off >= dest.len)off = dest.len - 1;
lstring* Src = (lstring*)malloc(sizeof(lstring)); lstring::lstring(Src); lstrcpy((*Src), src);
ull l0 = src.len - 1, off0 = 0; schar * o, *p = dest.string, *s = (*Src).string;
if (off != 0)off0 = off - 1;
for (ull i = 0; i < off0; ++i) { p = p->next; }
o = p, p = p->next;
for (ull i = 0; i < l0; ++i) { s = s->next; }
s->next = p, dest.len += src.len;
if (off == 0) { s->next = dest.string, dest.string = (*Src).string; return true; }
o->next = (*Src).string; return true;
}
inline bool lstrins_rear(lstring& dest, const lstring& src, ull off) {
if (src.len == 0)return false;
if (off >= dest.len)off = dest.len - 1;
lstring* Src = (lstring*)malloc(sizeof(lstring)); lstring::lstring(Src); lstrcpy((*Src), src);
ull l0 = src.len - 1; schar* o, * p = dest.string, * r = p, * s = (*Src).string;
for (ull i = 0; i < off; ++i) { p = p->next; }
o = p, p = p->next;
for (ull i = 0; i < l0; ++i) { s = s->next; }
s->next = p, dest.len += src.len;
o->next = (*Src).string; return true;
}
inline bool lstrdel(lstring& s, const ull& l, const ull& r) {
if (l > r || l >= s.len || r >= s.len)return false;
schar* p = s.string, * q, * t; ull l0 = 0;
if (l != 0)l0 = l - 1;
for (ull i = 0; i < l0; ++i)p = p->next;
t = p, s.len -= r - l + 1; if (l != 0)p = p->next;
for (ull i = l; i <= r; ++i) { q = p, p = p->next, free(q); }
if (l == 0) { s.string = p; return true; }
t->next = p; return true;
}
int main(){
d.seed(clock());
for (;;) {
l = x(d); for (ull i = 0; i < l; ++i) { str[i] = c(d); } str[l] = 0;
lstrassign(s, str);
printf("Generated char array str = \"%s\" and assigned it to link string s. The content of s is\n", str);
printlstr(s), putchar('\n');
printf("The length of s is %llu\n\n", s.len);
lstrcpy(t, s);
puts("Copied s to link string t. The content of t is");
printlstr(t), putchar('\n');
printf("The length of t is %llu\n\n", t.len);
clearlstr(t);
printf("Cleared link string t. Now the length of t is %llu. The content of t is\"", t.len), printlstr(t), puts("\"\n");
l = x(d); for (ull i = 0; i < l; ++i) { str[i] = c(d); } str[l] = 0;
lstrassign(t, str);
printf("Generated char array str = \"%s\" and assigned it to link string t. The content of t is\n", str);
printlstr(t), putchar('\n');
printf("The length of t is %llu\n\n", t.len);
cmpres = lstrcmp(s, t);
if (cmpres > 0)puts("The lexicographic order of s is greater than t.\n");
else if (cmpres < 0)puts("The lexicographic order of s is less than t.\n");
else puts("Link string s and t are equal.\n");
lstrcat(u, s, t);
puts("Link string s and t have been catenated and written to u. The content of u is");
printlstr(u), putchar('\n');
printf("The length of u is %llu\n\n", u.len);
a = randint(0ull, u.len), b = randint(0ull, u.len), v = sublstr(u, a, b);
printf("Got a substring v at range of [%llu, %llu] from link string u. The content of v is\n", a, b);
printlstr(v), putchar('\n');
printf("The length of v is %llu\n\n", v.len);
l = x(d); for (ull i = 0; i < l; ++i) { str[i] = c(d); } str[l] = 0;
a = randint(0ull, u.len), lstrins_front(u, str, a);
printf("Inserted char array str = \"%s\" before index %llu of link string u. The content of u is\n", str, a);
printlstr(u), putchar('\n');
printf("The length of u is %llu\n\n", u.len);
l = x(d); for (ull i = 0; i < l; ++i) { str[i] = c(d); } str[l] = 0;
a = randint(0ull, v.len), lstrins_rear(v, str, a);
printf("Inserted char array str = \"%s\" after index %llu of link string v. The content of v is\n", str, a);
printlstr(v), putchar('\n');
printf("The length of v is %llu\n\n", v.len);
a = randint(0ull, u.len), lstrins_front(u, s, a);
fputs("Inserted link string s \"", stdout); printlstr(s);
printf("\" before index %llu of link string u. The content of u is\n", a);
printlstr(u), putchar('\n');
printf("The length of u is %llu\n\n", u.len);
a = randint(0ull, u.len), lstrins_rear(v, t, a);
fputs("Inserted link string v \"", stdout); printlstr(t);
printf("\" after index %llu of link string v. The content of v is\n", a);
printlstr(v), putchar('\n');
printf("The length of v is %llu\n\n", v.len);
a = randint(0ull, u.len), b = randint(0ull, u.len);
if (lstrdel(u, a, b) == false)puts("Something wrong with parameters. Deleting failed.");
printf("Deleted a substring at range of [%llu, %llu] from link string u. The content of u is\n", a, b);
printlstr(u), putchar('\n');
printf("The length of u is %llu\n\n", u.len);
puts("Input any character except EOF to continue...");
if (getchar() == EOF)return 0;
getchar(), putchar('\n');
}
}