单词翻转(4种思路,C/C++代码)
2016-05-19 16:08
323 查看
输入一个英文句子,翻转句子中单词的顺序,要求单词内字符的顺序不变,句子中单词以空格隔开,为简单起见,标点符号和普通字母一样处理。例如:输入“I am a student.”则输出:“student. a am I”。
思路一:最后一个单词的位置是不用移动的。从后面往前面遍历,遇到第一个空格时,开始统计下一个单词的长度n,统计完成后将该单词后面的单词向前移动n位,并将该单词移动到字符串的末尾;依照这样的方式,直至遍历完整个字符串。
评:该方法的实现过程异常复杂,时间复杂度太高。
思路二:从后往前依次遍历源字符串src,每次遍历完一个单词后,直接将该单词整个拷贝到另一个字符串dst中,依次遍历原字符串,分别将每个独立的单词拷贝到dst中。
评:该算法的空间复杂度比较高,因为需要多申请一段空间dst来保存遍历的结果。
思路三:将整个字符串翻转,然后分别将字符串中的单个单词独立进行翻转。
思路四:三步反转法:先将每个单词分成独立的几部分,然后分别对它们进行翻转,返回将整个字符串进行翻转。(最后一步的翻转其实是可以省略的,直接将字符串从后往前输出即可)
评:思路三和四的思想是一样的,个人更喜欢第四种。
输入:“I am a student.”
中间结果:“I ma a .tneduts”
输出:“student. a am I”
C/C++代码
//输入“I am a student.”则输出:“student. a am I”。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string.h>
using namespace std;
void *reverse(char *src, char *dst)
{
char *p1, *p2;
if(src == NULL || dst == NULL)
{
return NULL;
}
//从src的最后一个字符开始遍历
p1 = src + strlen(src) - 1;
p2 = p1;
while (p1 != src)
{
if (*p1 == ' ')
{
int len = p2 - p1;//单词的长度
memcpy(dst, p1 + 1, len);
//每个单词的末尾加上一个空格
dst += len;
*dst++ = ' ';
p1--;
p2 = p1;
}
else
{
//不断将p1向前移动
p1--;
}
}
//最后一次拷贝单词
int len = p2 - p1 + 1;
memcpy(dst, p1, len);
dst += len;
*dst++ ='\0';
}
void print(char *s, int m)
{
for (int i = 0; i < m; i++)
{
if (s[i] == ' ')
cout << " ";
else
cout << s[i];
}
cout << endl;
}
int main()
{
char *dst;
dst = (char*)malloc(sizeof(char) * 10);
char a[] = "I am a student.";
//单词的长度
int n = strlen(a);
cout << "n=" << n << endl;
//显示未翻转前的字符串
print(a, n);
//单词翻转
reverse(a, dst);
//显示翻转之后的字符串
print(dst, n);
return 0;
}
附:
memcpy 函数用于把资源内存(src所指向的内存区域)拷贝到目标内存(dest所指向的内存区域);拷贝多少个?有一个count变量控制拷贝的字节数;
函数原型:void *memcpy(void *dest, void *src, unsigned int count);
用法:可以拷贝任何类型的对象,因为函数的参数类型是void*(未定义类型指针),也就是说传进去的实参可以是int*,short*,char*等等;但是由于函数拷贝的过程是一个字节一个字节的拷贝的,所以实际操作的时候要把void*强制转化为char*,这样在指针加的时候才会保证每次加一个字节。
思路一:最后一个单词的位置是不用移动的。从后面往前面遍历,遇到第一个空格时,开始统计下一个单词的长度n,统计完成后将该单词后面的单词向前移动n位,并将该单词移动到字符串的末尾;依照这样的方式,直至遍历完整个字符串。
评:该方法的实现过程异常复杂,时间复杂度太高。
思路二:从后往前依次遍历源字符串src,每次遍历完一个单词后,直接将该单词整个拷贝到另一个字符串dst中,依次遍历原字符串,分别将每个独立的单词拷贝到dst中。
评:该算法的空间复杂度比较高,因为需要多申请一段空间dst来保存遍历的结果。
思路三:将整个字符串翻转,然后分别将字符串中的单个单词独立进行翻转。
思路四:三步反转法:先将每个单词分成独立的几部分,然后分别对它们进行翻转,返回将整个字符串进行翻转。(最后一步的翻转其实是可以省略的,直接将字符串从后往前输出即可)
评:思路三和四的思想是一样的,个人更喜欢第四种。
输入:“I am a student.”
中间结果:“I ma a .tneduts”
输出:“student. a am I”
C/C++代码
//输入“I am a student.”则输出:“student. a am I”。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string.h>
using namespace std;
void *reverse(char *src, char *dst)
{
char *p1, *p2;
if(src == NULL || dst == NULL)
{
return NULL;
}
//从src的最后一个字符开始遍历
p1 = src + strlen(src) - 1;
p2 = p1;
while (p1 != src)
{
if (*p1 == ' ')
{
int len = p2 - p1;//单词的长度
memcpy(dst, p1 + 1, len);
//每个单词的末尾加上一个空格
dst += len;
*dst++ = ' ';
p1--;
p2 = p1;
}
else
{
//不断将p1向前移动
p1--;
}
}
//最后一次拷贝单词
int len = p2 - p1 + 1;
memcpy(dst, p1, len);
dst += len;
*dst++ ='\0';
}
void print(char *s, int m)
{
for (int i = 0; i < m; i++)
{
if (s[i] == ' ')
cout << " ";
else
cout << s[i];
}
cout << endl;
}
int main()
{
char *dst;
dst = (char*)malloc(sizeof(char) * 10);
char a[] = "I am a student.";
//单词的长度
int n = strlen(a);
cout << "n=" << n << endl;
//显示未翻转前的字符串
print(a, n);
//单词翻转
reverse(a, dst);
//显示翻转之后的字符串
print(dst, n);
return 0;
}
//三步反转法 #include"stdafx.h" #include<iostream> using namespace std; void print(char *s, int m) { for (int i = 0; i < m; i++) { cout << s[i]; } cout << endl; } //将每个单词进行翻转 void reverse(char *s,int low,int high) { while (low < high) { int tmp = s[high]; s[high] = s[low]; s[low] = tmp; low++; high--; } } int main() { int num = 0; int low, high; //cout << "请输入一个字符串:"; char a[] = "I am a student."; //单词的长度 int n = strlen(a); cout << "n=" << n << endl; //显示未翻转前的字符串 print(a, n); //将字符串分为独立的几个单词,并分别进行翻转 for (int i = 0; i <= n; i++) { if (a[i] == ' '||a[i]=='\0') { //单词翻转 reverse(a,i-num,i-1); num = 0; } else { num++; } } //中间结果 print(a, n); //显示翻转之后的字符串 for (int i = n-1; i >=0; i--) { cout << a[i]; } cout << endl; return 0; }
附:
memcpy 函数用于把资源内存(src所指向的内存区域)拷贝到目标内存(dest所指向的内存区域);拷贝多少个?有一个count变量控制拷贝的字节数;
函数原型:void *memcpy(void *dest, void *src, unsigned int count);
用法:可以拷贝任何类型的对象,因为函数的参数类型是void*(未定义类型指针),也就是说传进去的实参可以是int*,short*,char*等等;但是由于函数拷贝的过程是一个字节一个字节的拷贝的,所以实际操作的时候要把void*强制转化为char*,这样在指针加的时候才会保证每次加一个字节。
相关文章推荐
- 字符串翻转问题
- 【C语言】翻转单词序
- 单词翻转
- 剑指offer第42题:单词反转
- C++实现翻转单词顺序
- void,void *
- C语言柔性数组
- c语言,读取一个内容长度未知的文本文件。
- c++指针的指针和指针的引用
- C++ limits头文件
- C语言:标识符
- C++中的指针与引用详细解读
- C语言中数据类型所占字节数总结
- Eclipse支持 C++ 11
- C语言运算符优先级和口诀
- C语言:变量定义
- 【C++专题】static_cast, dynamic_cast, const_cast探讨
- C++中常见类型转换
- 1008. 数组元素循环右移问题 (20)
- 【C++】:关于C++的这些概念你知道吗?