当前位置:   article > 正文

数据结构——串_串的存储密度

串的存储密度

串又称字符串,是由零个或多个字符组成的有限序列,是一种特殊的线性表。由串中若干个连续字符组成的子序列称为子串。

利用字符数组或字符指针表示串:

  1. char str1[] = { 'a','b','c','d','\0' };
  2. char str2[] = "abcdef";
  3. char* str3 = str1;

上述三种表示串的方法其实就是顺序表的简化形式。由于在上述表达方法中,字符串的最后都有一个结束符“/0”,从而不需要指定顺序表的长度。

串的另一种表示方法是采用双向链表表示,称之为链串。存储密度为有效空间与所占用总空间的比值,若每个结点只存放一个字符,那么字符串的存储密度只有1/(2*4+1)=0.11(next,pre指针所占用空间都为4个字节),空间利用率低。
为提高空间效率,可以在每一个结点中存放多个字符。

在头文件<string.h>中有针对字符数组和字符指针所表示字符串的相关操作。例如,求字符串的长度(strlen)、字符串赋值(strcpy)、字符串比较(strcmp)、字符串连接(strcat)等。

链串的组织形式与一般的链表类似。主要的区别在于,链串中的一个节点可以存储多个字符。通常将链串中每个节点所存储的字符个数称为节点大小。

链串节点大小的选择与顺序串的格式选择类似。节点大小越大,则存储密度越大。但存储密度越大,一些操作(如插入、删除、替换等)有所不便,且可能引起大量字符移动,因此它适合于在串基本保持静态使用方式时采用。节点大小越小(如节点大小为1时),运算处理越方便,但存储密度下降。为简便起见,这里规定链串节点大小均为1。                                                                     

//str = (chainString)malloc(sizeof(csNode));

不采用该方式进行分配空间,会出现黄色警告

采用如下方式:

str = new csNode;

 代码如下所示:

  1. #include<iostream>
  2. using namespace std;
  3. typedef char datatype;
  4. typedef struct csNode {
  5. datatype data;
  6. csNode* next;
  7. csNode() :next(NULL) {
  8. data = '\0';
  9. };
  10. }*chainString;
  11. void cs_insert(chainString p, datatype ch) {
  12. chainString q = new csNode;
  13. if (q == NULL) {
  14. cout << "插入结点失败" << endl;
  15. return;
  16. }
  17. q->data = ch;
  18. q->next = p->next;
  19. p->next = q;
  20. }
  21. /*生成串*/
  22. void createChainString(chainString h, datatype cstr[], int n)
  23. {
  24. if (h == NULL) h = new csNode;
  25. for (int i = n - 1; i >= 0; i--)
  26. cs_insert(h, cstr[i]);
  27. }
  28. //串的第一个数据结点删除
  29. void cs_delete(chainString p) {
  30. if (p == NULL) return;
  31. chainString q = p->next;
  32. if (q == NULL)
  33. return;
  34. p->next = q->next;
  35. delete q;
  36. q = NULL;
  37. }
  38. /*摧毁串*/
  39. void destroyString(chainString& h)
  40. {
  41. while (h->next != NULL) {
  42. cs_delete(h);
  43. }
  44. delete h;
  45. h = NULL;
  46. }
  47. /*串的复制,t赋值*/
  48. void StrCopy(chainString& s, chainString t)
  49. {
  50. if (s == NULL) s = new csNode;
  51. chainString p = t->next;
  52. while (p != NULL)
  53. {
  54. cs_insert(s, p->data);
  55. p = p->next;
  56. }
  57. }
  58. /*判断串相等*/
  59. bool StrEqual(chainString s, chainString t)
  60. {
  61. chainString p = s->next, q = t->next;
  62. while (p != NULL && q != NULL && p->data == q->data)
  63. {
  64. p = p->next;
  65. q = q->next;
  66. }
  67. if (p == NULL || q == NULL) //表明此时已经扫描到串尾
  68. return true;
  69. else
  70. return false;
  71. }
  72. /*求串长*/
  73. int StrLength(chainString s)
  74. {
  75. int i = 0;
  76. chainString p = s->next;
  77. while (p != NULL)
  78. {
  79. i++;
  80. p = p->next;
  81. }
  82. return i;
  83. }
  84. /*串的连接,但不改变原本的s和t*/
  85. chainString ConCat(chainString s, chainString t)
  86. {
  87. chainString str, p, q, r;
  88. str = new csNode;
  89. r = str;
  90. //先将s存放到str中
  91. p = s->next;
  92. while (p != NULL)
  93. {
  94. q = new csNode;
  95. q->data = p->data;
  96. r->next = q; r = q; //通过r指针的不断移动,构建str的后面部分,str作为一个不变的头,进行遍历
  97. p = p->next;
  98. }
  99. //再循环利用变量将t也存入str中,即接在s之后
  100. p = t->next;
  101. while (p != NULL)
  102. {
  103. q = new csNode;
  104. q->data = p->data;
  105. r->next = q; r = q;
  106. p = p->next;
  107. }
  108. r->next = NULL;
  109. return str;
  110. }
  111. /*求子串*/
  112. chainString SubStr(chainString s, int i, int j)
  113. {
  114. chainString str, p, q, r;
  115. str = new csNode;
  116. str->next = NULL; //若不将str置为空串,则输入放入会出现异常
  117. r = str;
  118. if (i <= 0 || i > StrLength(s) || j<0 || j>StrLength(s) || j - i + 1 > StrLength(s))
  119. return str;
  120. //利用指向p先行遍历到位置i
  121. p = s->next;
  122. for (int k = 1; k < i; ++k)
  123. p = p->next;
  124. //在从位置i开始遍历到位置j取出子串
  125. for (int k = i; k <= j; ++k)
  126. {
  127. q = new csNode;
  128. q->data = p->data;
  129. r->next = q; r = q;
  130. p = p->next;
  131. }
  132. r->next = NULL;
  133. return str;
  134. }
  135. /*子串的插入*/
  136. chainString InsStr(chainString s, int i, chainString t)
  137. {
  138. int k = 1;
  139. chainString str, p, p1, q, r;
  140. str = new csNode;
  141. str->next = NULL;
  142. r = str;
  143. //判断下标i是否越界
  144. if (i <= 0 || i > StrLength(s) + 1)
  145. return str;
  146. //利用指针p,先将前0~i-1个字符存入str
  147. p = s->next;
  148. for (int k = 1; k < i; ++k)
  149. {
  150. q = new csNode;
  151. q->data = p->data;
  152. r->next = q; r = q;
  153. p = p->next;
  154. }
  155. //利用指针p1,将串t中的结点顺势放入str中
  156. p1 = t->next;
  157. while (p1 != NULL)
  158. {
  159. q = new csNode;
  160. q->data = p1->data;
  161. r->next = q; r = q;
  162. p1 = p1->next;
  163. }
  164. //此时的指针p,已然移动到i的位置,开始将后面的剩余结点继续存入串str中
  165. while (p != NULL)
  166. {
  167. q = new csNode;
  168. q->data = p->data;
  169. r->next = q; r = q;
  170. p = p->next;
  171. }
  172. r->next = NULL;
  173. return str;
  174. }
  175. /*子串的删除*/
  176. chainString DelStr(chainString s, int i, int j)
  177. {
  178. int k = 1;
  179. chainString str, p, q, r;
  180. str = new csNode;
  181. str->next = NULL;
  182. r = str;
  183. if (i <= 0 || i > StrLength(s) || j - i + 1 > StrLength(s))
  184. return str;
  185. //利用指针p,先将前0~i-1个字符存入str
  186. p = s->next;
  187. for (int k = 1; k < i; ++k)
  188. {
  189. q = new csNode;
  190. q->data = p->data;
  191. r->next = q; r = q;
  192. p = p->next;
  193. }
  194. //再利用指针p,直接遍历过j个位置
  195. for (k = i; k <= j; ++k)
  196. p = p->next;
  197. //此时的指针p,已然移动到j+1的位置,开始将后面的剩余结点继续存入串str中
  198. while (p != NULL)
  199. {
  200. q = new csNode;
  201. q->data = p->data;
  202. r->next = q; r = q;
  203. p = p->next;
  204. }
  205. r->next = NULL;
  206. return str;
  207. }
  208. /*子串的替换*/
  209. chainString RepStr(chainString s, int i, int j, chainString t)
  210. {
  211. int k = 1;
  212. chainString str, p, p1, q, r;
  213. str = new csNode;
  214. str->next = NULL;
  215. r = str;
  216. //判断下标i是否越界
  217. if (i <= 0 || i > StrLength(s) + 1 || j<0 || j - i + 1>StrLength(s))
  218. return str;
  219. //利用指针p,先将前0~i-1个字符存入str
  220. p = s->next;
  221. for (int k = 1; k < i; ++k)
  222. {
  223. q = new csNode;
  224. q->data = p->data; q->next = NULL;
  225. r->next = q; r = q;
  226. p = p->next;
  227. }
  228. for (k = i; k <= j; ++k)
  229. p = p->next; //直接删除原本串s中从第i位开始长度为j的那一子串
  230. //利用指针p1,将串t中的结点顺势放入str中
  231. p1 = t->next;
  232. while (p1 != NULL)
  233. {
  234. q = new csNode;
  235. q->data = p1->data; q->next = NULL;
  236. r->next = q; r = q;
  237. p1 = p1->next;
  238. }
  239. //此时的指针p,已然移动到i的位置,开始将后面的剩余结点继续存入串str中
  240. while (p != NULL)
  241. {
  242. q = new csNode;
  243. q->data = p->data; q->next = NULL;
  244. r->next = q; r = q;
  245. p = p->next;
  246. }
  247. r->next = NULL;
  248. return str;
  249. }
  250. /*输出串*/
  251. void DispStr(chainString s)
  252. {
  253. chainString p = s->next;
  254. while (p != NULL)
  255. {
  256. cout << p->data << endl;
  257. p = p->next;
  258. }
  259. cout << endl;
  260. }
  261. void test1()
  262. {
  263. printf("*测试串的生成*\n");
  264. chainString s1 = new csNode;
  265. datatype ch1[12] = "Hello World";
  266. createChainString(s1, ch1, 12);
  267. printf("串s初始化为:");
  268. DispStr(s1);
  269. printf("\n*测试串的复制*\n");
  270. chainString s2 = new csNode;
  271. datatype ch2[6] = "Frank";
  272. createChainString(s2, ch2, 6);
  273. StrCopy(s1, s2);
  274. printf("复制后的串s1为:");
  275. DispStr(s1);
  276. printf("\n*测试串是否相等*\n");
  277. chainString s3 = new csNode, s4 = new csNode, s5 = new csNode;
  278. datatype ch3[6] = "apple";
  279. datatype ch4[6] = "apple";
  280. datatype ch5[7] = "banana";
  281. createChainString(s3, ch3, 6);
  282. createChainString(s4, ch4, 6);
  283. createChainString(s5, ch5, 7);
  284. if (StrEqual(s3, s4))
  285. printf("s3与s4两串相等\n");
  286. else
  287. printf("s3与s4两串不相等\n");
  288. if (StrEqual(s3, s5))
  289. printf("s3与s5两串相等\n");
  290. else
  291. printf("s3与s5两串不相等\n");
  292. printf("\n*测试串的长度*\n");
  293. int len = StrLength(s5);
  294. printf("显示一下串s5:");
  295. DispStr(s5);
  296. printf("串s5的长度为:%d\n", len);
  297. printf("\n*测试串的连接*\n");
  298. chainString s6 = new csNode;
  299. chainString s7 = new csNode;
  300. chainString s8 = new csNode;
  301. datatype ch6[3] = "so";
  302. datatype ch7[6] = " good";
  303. createChainString(s6, ch6, 3);
  304. createChainString(s7, ch7, 6);
  305. s8 = ConCat(s6, s7);
  306. printf("串s6与串s7连接之后为:");
  307. DispStr(s8);
  308. }
  309. void test2()
  310. {
  311. printf("*测试求子串*\n");
  312. chainString s1 = new csNode, s2 = new csNode;
  313. datatype ch1[10] = "wonderful";
  314. createChainString(s1, ch1, 10);
  315. printf("初始化的串s1为:");
  316. DispStr(s1);
  317. printf("串s1从第2个字符开始的连续4个字符的子串为:");
  318. s2 = SubStr(s1, 2, 4);
  319. DispStr(s2);
  320. printf("\n*测试子串的插入*\n");
  321. chainString s3 = new csNode, s4 = new csNode;
  322. datatype ch3[10] = "ok";
  323. createChainString(s3, ch3, 10);
  324. printf("在串s1的第3个位置插入串s3之后为:");
  325. s4 = InsStr(s1, 3, s3);
  326. DispStr(s4);
  327. printf("\n*测试子串的删除*\n");
  328. chainString s5 = new csNode, s6 = new csNode;
  329. datatype ch5[10] = "fantistic";
  330. createChainString(s5, ch5, 10);
  331. printf("将串s5的第5个字符开始的长度为2的子串删除后为:");
  332. s6 = DelStr(s5, 5, 2);
  333. DispStr(s6);
  334. printf("\n*测试子串的替换*\n");
  335. chainString s7 = new csNode;
  336. chainString s8 = new csNode;
  337. chainString s9 = new csNode;
  338. datatype ch7[15] = "accountability";
  339. datatype ch8[3] = "le";
  340. createChainString(s7, ch7, 15);
  341. createChainString(s8, ch8, 3);
  342. printf("将串s7从第10个字符开始的长度为2的子串替换成s8后为:");
  343. s9 = RepStr(s7, 10, 5, s8);
  344. DispStr(s9);
  345. }
  346. int main()
  347. {
  348. test1();
  349. test2();
  350. }

 参考:

数据结构 | 串的存储结构之链串_Fire_Cloud_1的博客-CSDN博客https://blog.csdn.net/Fire_Cloud_1/article/details/127414613?spm=1001.2014.3001.5501C++: 形参的*& 与 *的理解_福桐的博客-CSDN博客_c++ 形参&https://blog.csdn.net/weixin_40597170/article/details/95788150?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%BD%A2%E5%8F%82%20&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-95788150.142%5Ev70%5Ejs_top,201%5Ev4%5Eadd_ask&spm=1018.2226.3001.4187

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/670449
推荐阅读
相关标签
  

闽ICP备14008679号