通过在网上找到的一些编程访谈挑战,我不得不编写一个算法来反转一个const char *并返回一个指向新char *的指针。我想我已经拥有它,但是为了让它正常工作,我不得不做一些不稳定的事情 - 基本上我必须自己解决这个空终止的角色。不知怎的,我觉得这是错的,但我很难过,我想知道是否有人可以帮助我:
char * reverse(const char * str)
{
int length = strlen(str);
char * reversed_string = new char[length+1];
for(int i = 0; i < length; ++i)
{
reversed_string[i] = str[(length-1) - i];
}
//need to null terminate the string
reversed_string[length] = '\0';
return reversed_string;
}
int main(int argc, char * argv[])
{
char * rev_str = reverse("Testing");
cout << "Your string reversed is this: " << rev_str << endl;
delete rev_str;
rev_str = 0;
return 0;
}
答案 0 :(得分:16)
<algorithm>
的 std::reverse
适用于字符串和char
数组:
string str = "Hello";
char chx[] = "Hello";
reverse(str.begin(), str.end());
reverse(chx, chx + strlen(chx));
cout << str << endl;
cout << chx << endl;
/编辑:当然,这会修改原始字符串。但STL要救援。以下内容创建一个新的反转字符串。不幸的是(?),如果没有创建额外的(隐式)副本,这在C char
数组上不起作用:
string reverse_string(string const& old) {
return string(old.rbegin(), old.rend());
}
cout << reverse_string("Hello") << endl;
答案 1 :(得分:14)
我曾经有过这个问题。这是我想到的第一个答案,但后续工作是“现在不用分配任何记忆就做到了。”
int length = strlen(string);
for(int i = 0; i < length/2; i++) {
char c = string[i];
string[i] = string[length - i];
string[length - i] = c;
}
编辑:有些人对不使用指针表示不屑。虽然不是完全最优的,但它更具可读性。其他人已进入指针解决方案,所以我不会在此重复。
一位评论者质疑,如果没有(基于堆栈的)持有单元用于交换,它应该是可行的。这样做的机制是按位异或。用
替换循环内部string[i] = string[i] ^ string[length - i];
string[length - i] = string[i] ^ string[length - i];
string[i] = string[i] ^ string[length - i];
但总的来说,现代编译器可以优化天真交换的局部变量。有关详细信息,请See Wikipedia
答案 2 :(得分:7)
if( string[0] )
{
char *end = string + strlen(string)-1;
while( start < end )
{
char temp = *string;
*string++ = *end;
*end-- = temp;
}
}
答案 3 :(得分:3)
呃?没有人用指针做到了吗?
char *reverse(const char *s) {
size_t n = strlen(s);
char *dest = new char[n + 1];
char *d = (dest + n - 1);
dest[n] = 0;
while (*s) {
*d-- = *s++
}
return dest;
}
希望多年的Java没有破坏我的C; - )
编辑 :用额外的var替换所有这些strlen调用。斯特伦这些天回来了什么? (谢谢plinth)。
答案 4 :(得分:3)
您的代码是直截了当且并不令人惊讶。一些事情:
换句话说:
char *dst = reversed_string + length;
*dst-- = '\0';
while (*src) {
*dst-- = *src++;
}
答案 5 :(得分:3)
我知道这是非常不可移植的,但x86汇编程序指令 bswap 允许您通过一条指令交换四个字节,这可能是一个提升代码的好途径。
这是如何让它与GCC合作的一个例子。
/*
* reverse.c
*
* $20081020 23:33 fernando DOT miguelez AT gmail DOT com$
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_CHARS 10 * 1024 * 1024
/*
* Borrowed from http://coding.derkeiler.com/Archive/Assembler/comp.lang.asm.x86/2007-03/msg00004.html
* GNU Compiler syntax
*/
inline uint32_t bswap(uint32_t val)
{
__asm__("bswap %0" : "=r" (val) : "0" (val));
return val;
}
char * reverseAsm(const char * str)
{
int i;
int length = strlen(str);
int dwordLength = length/4;
if(length % 4 != 0)
{
printf("Error: Input string length must be multiple of 4: %d\n", length);
return NULL;
}
char * reversed_string = (char *) malloc(length+1);
for(i = 0; i < dwordLength; i++)
{
*(((uint32_t *) reversed_string) + dwordLength - i - 1) = bswap(*(((uint32_t *) str) + i));
}
reversed_string[length] = '\0';
return reversed_string;
}
char * reverse(const char * str)
{
int i;
int length = strlen(str);
char * reversed_string = (char *) malloc(length+1);
for(i = 0; i < length; ++i)
{
reversed_string[i] = str[(length-1) - i];
}
//need to null terminate the string
reversed_string[length] = '\0';
return reversed_string;
}
int main(void)
{
int i;
char *reversed_str, *reversed_str2;
clock_t start, total;
char *str = (char *) malloc(MAX_CHARS+1);
str[MAX_CHARS] = '\0';
srand(time(0));
for(i = 0; i < MAX_CHARS; i++)
{
str[i] = 'A' + rand() % 26;
}
start = clock();
reversed_str = reverse(str);
total = clock() - start;
if(reversed_str != NULL)
{
printf("Total clock ticks to reverse %d chars with pure C method: %d\n", MAX_CHARS, total);
free(reversed_str);
}
start = clock();
reversed_str2 = reverseAsm(str);
total = clock() - start;
if(reversed_str2 != NULL)
{
printf("Total clock ticks to reverse %d chars with ASM+C method: %d\n", MAX_CHARS, total);
free(reversed_str2);
}
free(str);
return 0;
}
Cygwin下我旧计算机上的结果:
fer@fernando /cygdrive/c/tmp$ ./reverse.exe
Total clock ticks to reverse 10485760 chars with pure C method: 221
Total clock ticks to reverse 10485760 chars with ASM+C method: 140
答案 6 :(得分:2)
你不能(不应该)这样做:
string[i] ^= string[length - i] ^= string[i] ^= string[length - i];
来自:http://en.wikipedia.org/wiki/XOR_swap_algorithm#Code_example
答案 7 :(得分:2)
@Konrad Rudolph :(抱歉,我没有发表评论的“经验”)
我想指出STL提供reverse_copy()算法,类似于reverse()。你不需要像你那样引入临时的方法,只需分配一个合适大小的新char *。
答案 8 :(得分:1)
实际上,考虑到原始字符串未经修改的约束,我认为问题中给出的原始方法是最好的。所有这些花哨的方法都可以在人们发布的情况下进行逆转,但是一旦复制了给定的字符串,它们就会比简单地向后复制字符串效率低。
答案 9 :(得分:1)
我们之前使用过这个问题 - 结果令人惊讶地发现很多人无法做到这一点(即使有很高的C / C ++经验!)。我更喜欢就地变体,因为它节省了一些开销,并且还需要迭代strlen(s)/ 2个字符。
你在采访中的解决方案没问题。使用指针而不是数组语法的(正确的!)解决方案会更高一些,因为它在C / C ++编程中对指针显示出更高的舒适度。
次要的批评是指出strlen返回的size_t不是int,你应该在rev_str上使用delete []。
答案 10 :(得分:1)
WRT:“现在没有临时保持变量就行了”......也许这样的事情(现在保持数组索引):
int length = strlen(string);
for(int i = 0; i < length/2; i++) {
string[i] ^= string[length - i];
string[length - i] ^= string[i];
string[i] ^= string[length - i];
}
答案 11 :(得分:0)
当以面试官的身份提出这个问题时,我期待一个干净,易懂的解决方案,并可能会问如何使初始解决方案更有效率。我对'智能'解决方案不感兴趣。
我正在考虑的事情;让候选人在他们的循环中通过一个错误使其成为旧的,他们预先分配了足够的内存,他们检查错误的输入,他们是否使用足够的有效类型。
不幸的是,正如已经指出的那样,太多人甚至无法做到这一点。
答案 12 :(得分:0)
以上for循环有拼写错误。 检查循环变量i应该是&lt; =而不是&lt;,对于奇数no元素,othrewise将失败。 for(int i = 0; i&lt; = length / 2; ++ i)
答案 13 :(得分:0)
char * reverse(const char * str)
{
if (!str)
return NULL;
int length = strlen(str);
char * reversed_string = new char[length+1];
for(int i = 0; i < length/2; ++i)
{
reversed_string[i] = str[(length-1) - i];
reversed_string[(length-1) - i] = str[i];
}
//need to null terminate the string
reversed_string[length] = '\0';
return reversed_string;
}
一半的时间但相同的复杂性(注意可能会因一个错误而关闭)
答案 14 :(得分:0)
如果我正在进行面试,我会更加挑剔解决方案的质量,不仅仅是它的稳健性。
到目前为止提交的所有答案都会失败,如果传递一个空指针 - 大多数都会立即调用strlen()
一个可能的空指针 - 这可能会使您的进程发生段错误。
许多答案都是对表现的痴迷,以至于他们错过了问题的一个关键问题:反转const char *
,即你需要制作一个反向副本,不会就地逆转。如果需要复制,你会发现很难将迭代次数减半!
这是一个面试问题,所以我们想看看算法的细节,但在现实世界中,这只是强调了尽可能使用标准库的价值。
答案 15 :(得分:0)
不需要临时变量的方法
int length = strlen(string);
for(int i = 0; i < length/2; i++) {
string[i] ^= string[length - i] ^= string[i] ^= string[length - i];
}
答案 16 :(得分:0)
字符串已反转,没有临时变量。
static inline void
byteswap (char *a, char *b)
{
*a = *a^*b;
*b = *a^*b;
*a = *a^*b;
}
void
reverse (char *string)
{
char *end = string + strlen(string) - 1;
while (string < end) {
byteswap(string++, end--);
}
}
答案 17 :(得分:0)
它不会更高效,但您可以通过执行诸如将每个字母推入堆栈,然后将它们弹出到新分配的缓冲区中来展示数据结构的知识。
这需要两次传递和一个临时堆栈,但我可能会更信任自己,以便第一次做到这一点,然后不像上面那样做出一个错误的错误。
char* stringReverse(const char* sInput)
{
std::size_t nLen = strlen(sInput);
std::stack<char> charStack;
for(std::size_t i = 0; i < nLen; ++i)
{
charStack.push(sInput[i]);
}
char * result = new char[nLen + 1];
std::size_t counter = 0;
while (!charStack.empty())
{
result[counter++] = charStack.top();
charStack.pop();
}
result[counter] = '\0';
return result;
}
答案 18 :(得分:0)
我会解决它有点像这样(我的c有点生疏,但原谅我)
char *reverse( const char *source ) {
int len = strlen( source );
char *dest = new char[ len + 1 ];
int i = 0;
int j = len;
while( j > 0 ) {
dest[j--] = src[i++];
}
dest[i] = \0;
return dest;
}
答案 19 :(得分:0)
这很好用:
#include <algorithm>
#include <iostream>
#include <cstring>
void reverse_string(char *str) {
char *end = str + strlen(str) - 1;
while (str < end) {
std::iter_swap(str++, end--);
}
}
int main() {
char s[] = "this is a test";
reverse_string(s);
std::cout << "[" << s << "]" << std::endl;
}