绳索数据结构(字符串快速拼接)
2017-05-24 23:44
309 查看
原文地址:Ropes Data Structure (Fast String Concatenation)
字符串连接是一种十分常见的操作。当字符串以传统的方式(例如字符数组)存储的时候,连接操作需要花费O(n)的时间(在这里n是元字符串的长度)。
我们可以利用绳索数据结构减少拼接花费的时间。
绳索数据结构
绳索是一个二叉树,这个二叉树的节点包含除叶子节点以外,节点左边字符的个数。叶子节点包含的是字符串断开的子字符串(子字符串的长度是由用户自己确定的)。
如下图所示:
上图说明了字符串在内存中的存储方式。每个叶子节点都包含了原字符串的子字符串,其他所有的节点包含了这个节点左边节点的字符数目。将字符的数目保存到左边的背后思想是查找第i个位置的字符所需要的成本最小化。
优点
绳索可以很明显地降低拼接的成本。
与数组不一样,绳索不需要大块连续的内存。
绳索不需要额外O(n)的空间做插入、删除、查询等操作。
如果要恢复最后一次拼接,那么可以在O(1)内移除树的根节点。
缺点
源码的复杂度增加了。
很容易出现bug。
存储父节点需要额外的空间。
访问第i个字符的时间增加了。
现在我们看一种情况,它可以解释为什么绳索法适用于大型字符串数组。
已知两个字符串
例子:
方法一(普通法)
我们用字符串
输出:
时间复杂度:O(n)
下面我们用绳索来解决这个问题。
方法二(绳索法)
绳索法可以在常量时间内将两个字符串拼接在一起。
创建一个根节点(这个节点存储要拼接的新字符串的根节点)。
标记这个节点的左孩子,这个字符串的根节点出现在首位。
标记这个节点的右孩子,这个字符串的根节点出现在第二位。
就是这样的,因为这个方法只要求建立新节点,所以时间复杂度是O(1)。
考虑下图:
输出:
字符串连接是一种十分常见的操作。当字符串以传统的方式(例如字符数组)存储的时候,连接操作需要花费O(n)的时间(在这里n是元字符串的长度)。
我们可以利用绳索数据结构减少拼接花费的时间。
绳索数据结构
绳索是一个二叉树,这个二叉树的节点包含除叶子节点以外,节点左边字符的个数。叶子节点包含的是字符串断开的子字符串(子字符串的长度是由用户自己确定的)。
如下图所示:
上图说明了字符串在内存中的存储方式。每个叶子节点都包含了原字符串的子字符串,其他所有的节点包含了这个节点左边节点的字符数目。将字符的数目保存到左边的背后思想是查找第i个位置的字符所需要的成本最小化。
优点
绳索可以很明显地降低拼接的成本。
与数组不一样,绳索不需要大块连续的内存。
绳索不需要额外O(n)的空间做插入、删除、查询等操作。
如果要恢复最后一次拼接,那么可以在O(1)内移除树的根节点。
缺点
源码的复杂度增加了。
很容易出现bug。
存储父节点需要额外的空间。
访问第i个字符的时间增加了。
现在我们看一种情况,它可以解释为什么绳索法适用于大型字符串数组。
已知两个字符串
a[]与
b[],在
c[]中拼接它们。
例子:
Input : a[] = "This is ", b[] = "an apple" Output : "This is an apple" Input : a[] = "This is ", b[] = "geeksforgeeks" Output : "This is geeksforgeeks"
方法一(普通法)
我们用字符串
c[]存储拼接后的结果。我们首先遍历
a[]然后将
a[]中的所有字符全部拷贝到
c[]中,然后再把
b[]全部拷到
c[]中。
// Simple C++ program to concatenate two strings #include <iostream> using namespace std; // Function that concatenates strings a[0..n1-1] // and b[0..n2-1] and stores the result in c[] void concatenate(char a[], char b[], char c[], int n1, int n2) { // Copy characters of A[] to C[] int i; for (i=0; i<n1; i++) c[i] = a[i]; // Copy characters of B[] for (int j=0; j<n2; j++) c[i++] = b[j]; c[i] = '\0'; } // Driver code int main() { char a[] = "Hi This is geeksforgeeks. "; int n1 = sizeof(a)/sizeof(a[0]); char b[] = "You are welcome here."; int n2 = sizeof(b)/sizeof(b[0]); // Concatenate a[] and b[] and store result // in c[] char c[n1 + n2 - 1]; concatenate(a, b, c, n1, n2); for (int i=0; i<n1+n2-1; i++) cout << c[i]; return 0; }
输出:
This is geeksforgeeks
时间复杂度:O(n)
下面我们用绳索来解决这个问题。
方法二(绳索法)
绳索法可以在常量时间内将两个字符串拼接在一起。
创建一个根节点(这个节点存储要拼接的新字符串的根节点)。
标记这个节点的左孩子,这个字符串的根节点出现在首位。
标记这个节点的右孩子,这个字符串的根节点出现在第二位。
就是这样的,因为这个方法只要求建立新节点,所以时间复杂度是O(1)。
考虑下图:
// C++ program to concatenate two strings using // rope data structure. #include <bits/stdc++.h> using namespace std; // Maximum no. of characters to be put in leaf nodes const int LEAF_LEN = 2; // Rope structure class Rope { public: Rope *left, *right, *parent; char *str; int lCount; }; // Function that creates a Rope structure. // node --> Reference to pointer of current root node // l --> Left index of current substring (initially 0) // r --> Left index of current substring (initially n-1) // par --> Parent of current node (Initially NULL) void createRopeStructure(Rope *&node, Rope *par, char a[], int l, int r) { Rope *tmp = new Rope(); tmp->left = tmp->right = NULL; // We put half nodes in left subtree tmp->lCount = (r-l)/2; tmp->parent = par; // If string length is more if ((r-l) > LEAF_LEN) { tmp->str = NULL; node = tmp; int m = (l + r)/2; createRopeStructure(node->left, node, a, l, m); createRopeStructure(node->right, node, a, m+1, r); } else { node = tmp; int j = 0; tmp->str = new char[LEAF_LEN]; for (int i=l; i<=r; i++) tmp->str[j++] = a[i]; } } // Function that prints the string (leaf nodes) void printstring(Rope *r) { if (r==NULL) return; if (r->left==NULL && r->right==NULL) cout << r->str; printstring(r->left); printstring(r->right); } // Function that efficiently concatenates two strings // with roots root1 and root2 respectively. n1 is size of // string represented by root1. // root3 is going to store root of concatenated Rope. void concatenate(Rope *&root3, Rope *root1, Rope *root2, int n1) { // Create a new Rope node, and make root1 // and root2 as children of tmp. Rope *tmp = new Rope(); tmp->parent = NULL; tmp->left = root1; tmp->right = root2; root1->parent = root2->parent = tmp; tmp->lCount = n1; // Make string of tmp empty and update // reference r tmp->str = NULL; root3 = tmp; } // Driver code int main() { // Create a Rope tree for first string Rope *root1 = NULL; char a[] = "Hi This is geeksforgeeks. "; int n1 = sizeof(a)/sizeof(a[0]); createRopeStructure(root1, NULL, a, 0, n1-1); // Create a Rope tree for second string Rope *root2 = NULL; char b[] = "You are welcome here."; int n2 = sizeof(b)/sizeof(b[0]); createRopeStructure(root2, NULL, b, 0, n2-1); // Concatenate the two strings in root3. Rope *root3 = NULL; concatenate(root3, root1, root2, n1); // Print the new concatenated string printstring(root3); cout << endl; return 0; }
输出:
Hi This is geeksforgeeks. You are welcome here.
相关文章推荐
- C#利用 string.Join 泛型集合快速转换拼接字符串
- Python培训知识总结系列- 第二章Python数据结构第二部分,字符串拼接
- 数据结构:字符串的堆分配存储结构,基本操作实现和测试。
- MFC字符串類拼接的效率問題
- 利用UltraEdit快速将SQL语句转换为符合VB.NET语法格式字符串
- VB用copymemory快速交换两个字符串
- javascript利用正则快速找出两个字符串的不同字符
- VB中的字符串拼接
- 代码里使用字符串操作来拼接sql语句的坏处
- 小窍门:借助udl文件快速、准确获取数据库连接字符串
- 数据结构和字符串处理代码整理
- SAS应用技巧-快速在CATALOG的SCL中查找某字符串的方法
- VB中字符串数组快速复制的一种方法
- 旧文重整理:数据结构和字符串处理代码整理
- 传递数据结构参数和字符串参数时,同时传递长度
- [数据结构]第三次作业:字符串替换
- 一个asp快速字符串连接类
- JavaScript极速狂飙:组合拼接字符串的效率
- 利用正则快速找出两个字符串的不同字符
- js:字符串类型快速转化成数字类型和数字类型快速转化为字符串类型