• C++Primer中文版(第4版)第四章习题答案


    习题4.1 假设get_size是一个没有参数并返回int值的函数,下列哪些定义是非法的?为什么? unsigned buf_size = 1024 (a) int ia[buf_size]; (b) int ia[get_size()]; (c) int ia[4*7-14]; (d) char st[11] = "fundamental" ; 【解答】 (a)非法,buf_size是一个变量,不能用于定义数组的维数(维长度)。 (b)非法,get_size()是函数调用,不是常量表达式,不能用于定义数组的维数(维长度)。 (d)非法,存放字符串"fundamental"的数组必须有12个元素,st只有11个元素。 习题4.2 下列数组的值是什么? string sa[10]; int ia[10]; int main(){ string sa2[10]; int ia2[10]; } 【解答】 sa和sa2为元素类型为string的数组,自动调用string类的默认构造函数将各元素初始化为空字符串;ia为在函数体外定义的内置数组,各元素初始化为0;ia2为在函数体内定义的内置数组,各元素未初始化,其值不确定。 习题4.3 下列哪些定义是错误的? (a) int ia[7] = {0, 1, 1, 2, 3, 5, 8}; (b) vector ivec = {0, 1, 1, 2, 3, 5, 8}; (c) int ia2[] = ia; (d) int ia3[] = ivec; 【解答】 (b)错误。vector对象不能用这种方式进行初始化。 (c)错误。不能用一个数组来初始化另一个数组。 (d)错误。不能用vector对象来初始化数组。 习题4.4 如何初始化数组的一部分或全部元素? 【解答】 定义数组时可使用初始化列表(用花括号括住的一组以逗号分隔的元素初值)来初始化数组的部分或全部元素。如果是初始化全部元素,可以省略定义数组时方括号中给出的数组维数值。如果指定了数组维数,则初始化列表提供的元素个数不能超过维数值。如果数组维数大于列出的元素初值个数,则只初始化前面的数组元素,剩下的其他元素,若是内置类型则初始化为0,若是类类型则调用该类的默认构造函数进行初始化。字符数组既可以用一组由花括号括起来、逗号隔开的字符字面值进行初始化,也可以用一个字符串字面值进行初始化。 习题4.5 列出使用数组而不是vector的缺点。 【解答】 与vector类型相比,数组具有如下缺点:数组的长度是固定的,而且数组不提供获取其容量大小的size操作,也不提供自动添加元素的push_back操作。因此,程序员无法在程序运行时知道一个给定数组的长度,而且如果需要更改数组的长度,程序员只能创建一个更大的新数组,然后把原数组的所有元素复制到新数组的存储空间中去。与使用vector类型的程序相比,使用内置数组的程序更容易出错且难以调试。 习题4.6 下面的程序段企图将下标值赋给数组的每个元素,其中在下标操作上有一些错误,请指出这些错误。 const size_t array_size = 10 ; int ia[array_size]; for (size_t ix = 1; ix <= array_size; ++ix) ia[ix] = ix ; 【解答】 该程序段的错误是:数组下标使用越界。 根据数组ia的定义,该数组的下标值应该是0~9(即array_size-1),而不是从1到array_size,因此其中的for语句出错,可更正如下: for (size_t ix = 0; ix < array_size; ++ix) ia[ix] = ix ; 习题4.7 编写必要的代码将一个数组赋给另一个数组,然后把这段代码改用vector实现。考虑如何将一个vector赋给另一个vector。 【解答】 将一个数组赋给另一个数组,就是将一个数组的元素逐个赋值给另一数组的对应元素,可用如下代码实现: int main() { const size_t array_size = 10; int ia1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int ia2[array_size]; for (size_t ix = 0; ix != array_size; ++ix) ia2[ix] = ia1[ix]; return 0; } 将一个vector赋给另一个vector,也是将一个vector的元素逐个赋值给另一vector的对应元素,可用如下代码实现: //将一个vector赋值给另一vector //使用迭代器访问vector中的元素 #include using namespace std; int main() { vector ivec1(10, 20);//每个元素初始化为20 vector ivec2; for (vector::iterator iter = ivec1.begin(); iter != ivec1.end(); ++iter) ivec2.push_back(*iter); return 0; } 习题4.8 编写程序判断两个数组是否相等,然后编写一段类似的程序比较两个vector。 【解答】 判断两个数组是否相等,可用如下程序: //判断两个数组是否相等 #include using namespace std; int main() { const int arr_size = 6; int ia1[arr_size], ia2[arr_size]; size_t ix; //读入两个数组的元素值 cout << "Enter " << arr_size << " numbers for array1:" << endl; for (ix = 0; ix != arr_size; ++ix) cin >> ia1[ix]; cout << "Enter " << arr_size << " numbers for array2:" << endl; for (ix = 0; ix != arr_size; ++ix) cin >> ia2[ix]; //判断两个数组是否相等 for (ix = 0; ix != arr_size; ++ix) if (ia1[ix] != ia2[ix]) { cout << "Array1 is not equal to array2." << endl; return 0; } cout << "Array1 is equal to array2." << endl; return 0; } 判断两个vector是否相等,可用如下程序: //判断两个vector是否相等 //使用迭代器访问vector中的元素 #include #include using namespace std; int main() { vector ivec1, ivec2; int ival; //读入两个vector的元素值 cout << "Enter numbers for vector1(-1 to end):" << endl; cin >> ival; while (ival != -1) { ivec1.push_back(ival); cin >> ival; } cout << "Enter numbers for vector2(-1 to end):" << endl; cin >> ival; while (ival != -1) { ivec2.push_back(ival); cin >> ival; } //判断两个vector是否相等 if (ivec1.size() != ivec2.size()) //长度不等的vector不相等 cout << "Vector1 is not equal to vector2." << endl; else if (ivec1.size() == 0) //长度都为0的vector相等 cout << "Vector1 is equal to vector2." << endl; else {//两个vector长度相等且不为0 vector::iterator iter1, iter2; iter1 = ivec1.begin(); iter2 = ivec2.begin(); while (*iter1 == *iter2 && iter1 != ivec1.end() && iter2 != ivec2.end()) { ++iter1; ++iter2; } if (iter1 == ivec1.end())//所有元素都相等 cout << "Vector1 is equal to vector2." << endl; else cout << "Vector1 is not equal to vector2." << endl; } return 0; } 习题4.9 编写程序定义一个有10个int型元素的数组,并以元素在数组中的位置作为各元素的初值。 【解答】 //定义一个有10个int型元素的数组, //并以元素在数组中的位置(1~10)作为各元素的初值 int main() { const int array_size = 10; int ia[array_size]; for (size_t ix = 0; ix != array_size; ++ix) ia[ix] = ix+1; return 0; } 习题4.10 下面提供了两种指针声明的形式,解释宁愿使用第一种形式的原因: int *ip; // good practice int* ip; // legal but misleading 【解答】 第一种形式强调了ip是一个指针,这种形式在阅读时不易引起误解,尤其是当一个语句中同时定义了多个变量时。 习题4.11 解释下列声明语句,并指出哪些是非法的,为什么? (a) int* ip; (b) string s, *sp = 0; (c) int i; double* dp = &i; (d) int* ip, ip2; (e) const int i = 0, *p = i; (f) string *p = NULL; 【解答】 (a)合法。定义了一个指向int型对象的指针ip。 (b)合法。定义了string对象s和指向string型对象的指针sp,sp初始化为0值。 (c)非法。dp为指向double型对象的指针,不能用int型对象i的地址进行初始化。 (d)合法。定义了int对象ip2和指向int型对象的指针ip。 (e)合法。定义了const int型对象i和指向const int型对象的指针p,i初始化为0,p初始化为0。 (f)合法。定义了指向string型对象的指针p,并将其初始化为0值。 习题4.12 已知一指针p,你可以确定该指针是否指向一个有效的对象吗?如果可以,如何确定?如果不可以,请说明原因。 【解答】 无法确定某指针是否指向一个有效对象。因为,在C++语言中,无法检测指针是否未被初始化,也无法区分一个地址是有效地址,还是由指针所分配的存储空间中存放的不确定值的二进制位形成的地址。 习题4.13 下列代码中,为什么第一个指针的初始化是合法的,而第二个则不合法? int i = 42; void *p = &i; long *lp = &i; 【解答】 具有void*类型的指针可以保存任意类型对象的地址,因此p的初始化是合法的;而指向long型对象的指针不能用int型对象的地址来初始化,因此lp的初始化不合法。 习题4.14 编写代码修改指针的值;然后再编写代码修改指针所指对象的值。 【解答】 下列代码修改指针的值: int *ip; int ival1, ival2; ip = &ival1; ip = &ival2; 下列代码修改指针所指对象的值: int ival = 0; int *ip = &ival; *ip = 8; 习题4.15 解释指针和引用的主要区别。 【解答】 使用引用(reference)和指针(pointer)都可间接访问另一个值,但它们之间存在两个重要区别:(1)引用总是指向某个确定对象(事实上,引用就是该对象的别名),定义引用时没有进行初始化会出现编译错误;(2) 赋值行为上存在差异:给引用赋值修改的是该引用所关联的对象的值,而不是使该引用与另一个对象关联。引用一经初始化,就始终指向同一个特定对象。给指针赋值修改的是指针对象本身,也就是使该指针指向另一对象,指针在不同时刻可指向不同的对象(只要保证类型匹配)。 习题4.16 下列程序段实现什么功能? int i = 42, j = 1024; int *p1 = &i, *p2 = &j; *p2 = *p1 * * p2; *p1 *= *p1; 【解答】 该程序段使得i被赋值为42的平方,j被赋值为42与1024的乘积。 习题4.17 已知p1和p2指向同一个数组中的元素,下面语句实现什么功能? p1 += p2 – p1; 当p1和p2具有什么值时这个语句是非法的? 【解答】 此语句使得p1也指向p2原来所指向的元素。原则上说,只要p1和p2的类型相同,则该语句始终是合法的。只有当p1和p2不是同类型指针时,该语句才不合法(不能进行-操作)。 但是,如果p1和p2不是指向同一个数组中的元素,则这个语句的执行结果可能是错误的。因为 -操作的结果类型ptrdiff_t只能保证足以存放同一数组中两个指针之间的差距。如果p1和p2不是指向同一个数组中的元素,则-操作的结果有可能超出ptrdiff_t类型的表示范围而产生溢出,从而该语句的执行结果不能保证p1指向p2原来所指向的元素(甚至不能保证p1为有效指针)。 习题4.18 编写程序,使用指针把一个int型数组的所有元素设置为0。 【解答】 // 使用指针把一个int型数组的所有元素设置为0 int main() { const size_t arr_size = 8; int int_arr[arr_size] = { 0, 1, 2, 3, 4, 5, 6, 7 }; // pbegin指向第一个元素,pend指向最后一个元素的下一内存位置 for (int *pbegin = int_arr, *pend = int_arr + arr_size; pbegin != pend; ++pbegin) *pbegin = 0; // 当前元素置0 return 0; } 习题4.19 解释下列5个定义的含义,指出其中哪些定义是非法的: (a) int i; (b) const int ic; (c) const int *pic; (d) int *const cpi; (e) const int *const cpic; 【解答】 (a) 合法:定义了int型对象i。 (b) 非法:定义const对象时必须进行初始化,但ic没有初始化。 (c) 合法:定义了指向int型const对象的指针pic。 (d) 非法:因为cpi被定义为指向int型对象的const指针,但该指针没有初始化。 (e) 非法:因为cpic被定义为指向int型const对象的const指针,但该指针没有初始化。 习题4.20 下列哪些初始化是合法的?为什么? (a) int i = -1; (b) const int ic = i ; (c) const int *pic = ⁣ (d) int *const cpi = ⁣ (e) const int *const cpic = ⁣ 【解答】 (a) 合法:定义了一个int型对象i,并用int型字面值-1对其进行初始化。 (b) 合法:定义了一个int型const对象ic,并用int型对象对其进行初始化。 (c) 合法:定义了一个指向int型const对象的指针pic,并用ic的地址对其进行初始化。 (d) 不合法:cpi是一个指向int型对象的const指针,不能用const int型对象ic的地址对其进行初始化。 (e) 合法:定义了一个指向int型const对象的const指针cpic,并用ic的地址对其进行初始化。 习题4.21 根据上述定义,下列哪些赋值运算是合法的?为什么? (a) i = ic; (b) pic = ⁣ (c) cpi = pic; (d) pic = cpic; (e) cpic = ⁣ (f) ic = *cpic; 【解答】 (a)、(b)、(d)合法。 (c)、(e)、(f)均不合法,因为cpi、cpic和ic都是const变量(常量),常量不能被赋值。 习题4.22 解释下列两个while循环的差别: const char *cp = "hello"; int cnt; while (cp) { ++cnt; ++cp; } while (*cp) { ++cnt; ++cp; } 【解答】 两个while循环的差别为:前者的循环结束条件是cp为0值(即指针cp为0值);后者的循环结束条件是cp所指向的字符为0值(即cp所指向的字符为字符串结束符null(即'\0'))。因此后者能正确地计算出字符串"hello"中有效字符的数目(放在cnt中),而前者的执行是不确定的。 注意,题目中的代码还有一个小问题,即cnt没有初始化为0值。 习题4.23 下列程序实现什么功能? const char ca[] = {'h', 'e', 'l', 'l', 'o'}; const char *cp = ca ; while (*cp) { cout << *cp << endl; ++cp; } 【解答】 该程序段从数组ca的起始地址(即字符'h'的存储地址)开始,输出一段内存中存放的字符,每行输出一个字符,直至存放0值(null)的字节为止。(注意,输出的内容一般来说要多于5个字符,因为字符数组ca中没有null结束符。) 习题4.24 解释strcpy和strncpy的差别在哪里,各自的优缺点是什么? 【解答】 strcpy和strncpy的差别在于:前者复制整个指定的字符串,后者只复制指定字符串中指定数目的字符。 strcpy比较简单,而使用strncpy可以适当地控制复制字符的数目,因此比strcpy更为安全。 习题4.25 编写程序比较两个string类型的字符串,然后编写另一个程序比较两个C风格字符串的值。 【解答】 比较两个string类型的字符串的程序如下: //比较两个string 类型的字符串 #include #include using namespace std; int main() { string str1, str2; //输入两个字符串 cout << "Enter two strings:" << endl; cin >> str1 >> str2; //比较两个字符串 if (str1 > str2) cout << "\"" << str1 << "\"" << " is bigger than " << "\"" << str2 << "\"" << endl; else if (str1 < str2) cout << "\"" << str2 << "\"" << " is bigger than " << "\"" << str1 << "\"" << endl; else cout << "They are equal" << endl; return 0; } 比较两个C风格字符串的程序如下: //比较两个C风格字符串的值 #include #include using namespace std; int main() { //char *str1 = "string1", *str2 = "string2"; const int str_size = 80; char *str1, *str2; //为两个字符串分配内存 str1 = new char[str_size]; str2 = new char[str_size]; if (str1 == NULL || str2 == NULL) { cout << "No enough memory!" << endl; return -1; } //输入两个字符串 cout << "Enter two strings:" << endl; cin >> str1 >> str2; //比较两个字符串 int result; result = strcmp(str1, str2); if (result > 0) cout << "\"" << str1 << "\"" << " is bigger than " << "\"" << str2 << "\"" << endl; else if (result < 0) cout << "\"" << str2 << "\"" << " is bigger than " << "\"" << str1 << "\"" << endl; else cout << "They are equal" << endl; //释放字符串所占用的内存 delete [] str1 ; delete [] str2 ; return 0; } 注意,此程序中使用了内存的动态分配与释放(见4.3.1节)。如果不用内存的动态分配与释放,可将主函数中第2、3两行代码、有关内存分配与释放的代码以及输入字符串的代码注释掉,再将主函数中第一行代码 //char *str1 = "string1", *str2 = "string2"; 前的双斜线去掉即可。 习题4.26 编写程序从标准输入设备读入一个string类型的字符串。考虑如何编程实现从标准输入设备读入一个C风格字符串。 【解答】 从标准输入设备读入一个string类型字符串的程序段: string str; cin >> str; 从标准输入设备读入一个C风格字符串可如下实现: const int str_size = 80; char str[str_size]; cin >> str; 习题4.27 假设有下面的new表达式,请问如何释放pa? int *pa = new int[10]; 【解答】 用语句delete [] pa;释放pa所指向的数组空间。 习题4.28 编写程序由从标准输入设备读入的元素数据建立一个int型vector对象,然后动态创建一个与该vector对象大小一致的数组,把vector对象的所有元素复制给新数组。 【解答】 // 从标准输入设备读入的元素数据建立一个int型vector对象, // 然后动态创建一个与该vector对象大小一致的数组, // 把vector对象的所有元素复制给新数组 #include #include using namespace std; int main() { vector ivec; int ival; //读入元素数据并建立vector cout << "Enter numbers:(Ctrl+Z to end)" << endl; while (cin >> ival) ivec.push_back(ival); //动态创建数组 int *pia = new int[ivec.size()]; //复制元素 int *tp = pia; for (vector::iterator iter = ivec.begin(); iter != ivec.end(); ++iter, ++tp) *tp = *iter; //释放动态数组的内存 delete [] pia; return 0; } 习题4.29 对本节第5条框中的两段程序: (a) 解释这两段程序实现的功能。 (b) 平均来说,使用string类型的程序执行速度要比用C风格字符串的快很多,在我们用了5年的PC机上其平均执行速度分别是: user 0.47 # string class user 2.55 # C-style character string 你预计的也一样吗?请说明原因。 【解答】 (a) 这两段程序的功能是:执行一个循环次数为1000000的循环,在该循环的循环体中:创建一个新字符串,将一个已存在的字符串复制给新字符串,然后比较两个字符串,最后释放新字符串。 (b) 使用C风格字符串的程序需要自己管理内存的分配和释放,而使用string类型的程序由系统自动进行内存的分配和释放,因此比使用C风格字符串的程序要简短,执行速度也要快一些。 习题4.30 编写程序连接两个C风格字符串字面值,把结果存储在一个C风格字符串中。然后再编写程序连接两个string类型字符串,这两个string类型字符串与前面的C风格字符串字面值具有相同的内容。 【解答】 连接两个C风格字符串字面值的程序如下: // 连接两个C风格字符串字面值, // 把结果存储在一个C风格字符串中 #include int main() { const char *cp1 = "Mary and Linda "; const char *cp2 = "are firends."; size_t len = strlen(cp1) + strlen(cp2); char *result_str = new char[len+1]; strcpy(result_str, cp1); strcat(result_str, cp2); delete [] result_str; return 0; } 相应的连接两个string类型字符串的程序如下: // 连接两个string类型字符串 #include using namespace std; int main() { const string str1("Mary and Linda "); const string str2("are firends."); string result_str; result_str = str1; result_str += str2; return 0; } 习题4.31 编写程序从标准输入设备读入字符串,并把该串存放在字符数组中。描述你的程序如何处理可变长的输入。提供比你分配的数组长度长的字符串数据测试你的程序。 【解答】 // 从标准输入设备读入字符串,并把该串存放在字符数组中 #include #include #include using namespace std; int main() { string in_str;// 用于读入字符串的string对象 const size_t str_size = 10; char result_str[str_size+1]; // 读入字符串 cout << "Enter a string(<=" << str_size << " characters):" << endl; cin >> in_str; // 计算需复制的字符的数目 size_t len = strlen(in_str.c_str()); if (len > str_size) { len = str_size; cout << "String is longer than " << str_size << " characters and is stored only " << str_size << " characters!" << endl; } // 复制len个字符至字符数组result_str strncpy(result_str, in_str.c_str(), len); // 在末尾加上一个空字符(null字符) result_str[len+1] = '\0'; return 0; } 为了接受可变长的输入,程序中用一个string对象存放读入的字符串,然后使用 strncpy函数将该对象的适当内容复制到字符数组中。因为字符数组的长度是固定的,因此首先计算字符串的长度。若该长度小于或等于字符数组可容纳字符串的长度,则复制整个字符串至字符数组,否则,根据数组的长度,复制字符串中前面部分的字符,以防止溢出。 注意,上述给出的是满足题目要求的一个解答,事实上,如果希望接受可变长的输入并完整地存放到字符数组中,可以采用动态创建数组来实现。 习题4.32 编写程序用int型数组初始化vector对象。 【解答】 // 用int型数组初始化vector对象 #include #include using namespace std; int main() { const size_t arr_size = 8; int int_arr[arr_size]; // 输入数组元素 cout << "Enter " << arr_size << " numbers:" << endl; for (size_t ix = 0; ix != arr_size; ++ix) cin >> int_arr[ix]; // 用int型数组初始化vector对象 vector ivec(int_arr, int_arr + arr_size); return 0; } 习题4.33 编写程序把int型vector复制给int型数组。 【解答】 // 把int型vector复制给int型数组 #include #include using namespace std; int main() { vector ivec; int ival; // 输入vector元素 cout << "Enter numbers: (Ctrl+Z to end)" << endl; while (cin >> ival) ivec.push_back(ival); // 创建数组 int *parr = new int[ivec.size()]; // 复制元素 size_t ix = 0; for (vector::iterator iter = ivec.begin(); iter != ivec.end(); ++iter, ++ix) parr[ix] = *iter; // 释放数组 delete [] parr; return 0; } 习题4.34 编写程序读入一组string类型的数据,并将它们存储在vector中。接着,把该 vector对象复制给一个字符指针数组。为vector中的每个元素创建一个新的字符数组,并把该vector 元素的数据复制到相应的字符数组中,最后把指向该数组的指针插入字符指针数组。 【解答】 //4-34.cpp //读入一组string类型的数据,并将它们存储在vector中。 //接着,把该vector对象复制给一个字符指针数组。 //为vector中的每个元素创建一个新的字符数组, //并把该vector元素的数据复制到相应的字符数组中, //最后把指向该数组的指针插入字符指针数组 #include #include #include using namespace std; int main() { vector svec; string str; // 输入vector元素 cout << "Enter strings:(Ctrl+Z to end)" << endl; while (cin >> str) svec.push_back(str); // 创建字符指针数组 char **parr = new char*[svec.size()]; // 处理vector元素 size_t ix = 0; for (vector::iterator iter = svec.begin(); iter != svec.end(); ++iter, ++ix) { // 创建字符数组 char *p = new char[(*iter).size()+1]; // 复制vector元素的数据到字符数组 strcpy(p, (*iter).c_str()); // 将指向该字符数组的指针插入到字符指针数组 parr[ix] = p; } // 释放各个字符数组 for (ix =0; ix != svec.size(); ++ix) delete [] parr[ix]; // 释放字符指针数组 delete [] parr; return 0; } 习题4.35 输出习题4.34中建立的vector对象和数组的内容。输出数组后,记得释放字符数组。 【解答】 //4-35.cpp //读入一组string类型的数据,并将它们存储在vector中。 //接着,把该vector对象复制给一个字符指针数组: //为vector中的每个元素创建一个新的字符数组, //并把该vector元素的数据复制到相应的字符数组中, //然后把指向该数组的指针插入字符指针数组。 //输出建立的vector对象和数组的内容 #include #include #include using namespace std; int main() { vector svec; string str; // 输入vector元素 cout << "Enter strings:(Ctrl+Z to end)" << endl; while (cin >> str) svec.push_back(str); // 创建字符指针数组 char **parr = new char*[svec.size()]; // 处理vector元素 size_t ix = 0; for (vector::iterator iter = svec.begin(); iter != svec.end(); ++iter, ++ix) { // 创建字符数组 char *p = new char[(*iter).size()+1]; // 复制vector元素的数据到字符数组 strcpy(p, (*iter).c_str()); // 将指向该字符数组的指针插入到字符指针数组 parr[ix] = p; } // 输出vector对象的内容 cout << "Content of vector:" << endl; for (vector::iterator iter2 = svec.begin(); iter2 != svec.end(); ++iter2) cout << *iter2 << endl; // 输出字符数组的内容 cout << "Content of character arrays:" << endl; for (ix =0; ix != svec.size(); ++ix) cout << parr[ix] << endl; // 释放各个字符数组 for (ix =0; ix != svec.size(); ++ix) delete [] parr[ix]; // 释放字符指针数组 delete [] parr; return 0; } 习题4.36 重写程序输出ia数组的内容,要求在外层循环中不能使用typedef定义的类型。 【解答】 //4-36.cpp //重写程序输出ia数组的内容 //在外层循环中不使用typedef定义的类型 #include using namespace std; int main() { int ia[3][4] = { // 3个元素,每个元素是一个有4个int元素的数组 {0, 1, 2, 3} , // 0行的初始化列表 {4, 5, 6, 7} , // 1行的初始化列表 {8, 9, 10, 11} // 2行的初始化列表 }; int (*p)[4]; for (p = ia; p != ia + 3; ++p) for (int *q = *p; q != *p + 4; ++q) cout << *q << endl; return 0; }
  • 相关阅读:
    5. Longest Palindromic Substring
    4. Median of Two Sorted Arrays(topK-logk)
    apache开源项目--Derby
    apache开源项目--Apache Drill
    apache开源项目-- OODT
    apache开源项目--Mavibot
    apache开源项目--ApacheDS
    apache开源项目--TIKA
    apache开源项目--Mahout
    apache开源项目--Jackrabbit
  • 原文地址:https://www.cnblogs.com/piao/p/1959687.html
Copyright © 2020-2023  润新知