编写递归功能将给定的字符串转换为代表的数字
在此代码中,我想通过使用递归函数
将字符串
转换为整数
,但它在Negetive中给出了输出。
#include <iostream>
using namespace std;
int convert1(string s) {
if (s.length() == 1) {
int i = s[0] - '0';
return i;
}
int so = convert1(s.substr(0, s.length() - 1));
int num = s[s.length()] - '0';
int ans = so * 10 + num;
return (int)ans;
}
int main()
{
string s;
cin >> s;
cout << convert1(s) << endl;
}
In this code, I want to convert the string
into integer
by using recursive function
but it is giving output in negetive.
#include <iostream>
using namespace std;
int convert1(string s) {
if (s.length() == 1) {
int i = s[0] - '0';
return i;
}
int so = convert1(s.substr(0, s.length() - 1));
int num = s[s.length()] - '0';
int ans = so * 10 + num;
return (int)ans;
}
int main()
{
string s;
cin >> s;
cout << convert1(s) << endl;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您尝试打印
s [s.length()]
每次调用convert1
时,您会发现它是打印0
。然后,您从中减去'0''
的值(48
)。假设我们尝试转换
“ 12”
。长度是不是 1,因此我们调用
convert1
on“ 1”
。是长度1的,所以我们返回
1
。因此,如果
so
是1
,并且s [s.length()]
is0
,则num
是-48
和so * 10 + num
评估1 * 10-48
是-38
。对于两个数字的输入,您将始终看到第一个数字时间10,减48。对于三位数的数字,您会看到(第一个数字 * 10负48)乘以10个减去48。此模式继续进行。如果第一个数字足够大,则乘以10个减去48的数字会产生正数。如果足够大,正面数字会继续通过递归传播。如果它们的变小大于48,那么一旦结果为负,它将变得更大,因为负数会更递归呼叫。
与您做事的方式相反,您可以在
Convert1
中使用累加器参数。每次递归调用该函数时,我们都会通过将其乘以10并添加第一个数字的值来更新累加器,并通过取下字符串的“尾巴”来更新字符串。
或者更好,但与原始内容相距甚远,我们在字符串为空时返回累加器。
此尾部递归的好处是,此功能(如果由像样的编译器正确优化)可以在恒定的堆栈空间中运行。尽管在这种情况下是学术性的,因为
int
类型将在堆栈溢出之前溢出。If you try printing
s[s.length()]
each time you callconvert1
, you'll see that it's printing0
. And then you're subtracting the value of'0'
(48
) from that.Let's say we try to convert
"12"
.The length is not 1, so we call
convert1
on"1"
.That is of length 1, so we return
1
.So, if
so
is1
, ands[s.length()]
is0
, thennum
is-48
andso * 10 + num
evaluates to1 * 10 - 48
which is-38
.For a two digit number input, you will always see the first digit times 10, minus 48. For a three digit number, you'll see (the first digit * ten minus 48) times 10 minus 48. This pattern continues on. If the first digit is large enough, it times 10 minus 48 creates a positive number. If that's large enough, positive numbers continue to propagate through the recursion. If they ever get smaller than 48, then once the result is negative, it will just get larger as a negative number the more recursive calls are made.
As opposed to the way you have done things, you can employ an accumulator parameter in
convert1
.Each time the function is recursively called, we update the accumulator by multiplying it by ten and adding the value of the first digit, and update the string by taking the "tail" of the string.
Or better, but a little bit further from your original, we return the accumulator when the string is empty.
The benefit of this tail recursion is that this function (if properly optimized by a decent compiler) can run in constant stack space. Though it's academic in this case as the
int
type will overflow before a stack overflow.正常的递归方式
由于某种原因,
The normal way
Recursive for some reason
计算最后一个数字时,
您将对字符串的范围访问。将其更改为
,您的代码有效。效率低下。
您可以在每次递归中创建一个新的子字符串。有两种改进的方法:
制作一个辅助功能,可以使字符串的副本复制,然后调用递归功能。递归功能采用
std :: String&amp; S
然后可以使用s.pop_back()
。作为一方面,助手功能可以轻松处理以“ - ”开头的字符串。无论如何,你应该有这个助手。将参数更改为
std :: string_view
然后,它只是字符串中的引用,子字符串只会收缩该引用。字符串从未复制。实际上,这是唯一的变化,只需更改std :: String
std :: String_view
and done。我认为
std :: string_view
是要走的方法,但需要C ++ 17。将其与助手相结合,以处理“ - ”。接下来的事情是
s [s.length()-1]
,可以写为s.back()
。可以保管一些打字,没有逐个错误的风险。那么您终止递归的状况过于复杂。您可以
以额外的递归电话为代替编写。另一方面,这允许解析“”。不确定哪种方式更快,更简单的测试可能会平衡额外的递归调用。我喜欢它,因为它不会重复数字转换代码,而是键入的较少。
接下来,如果您使用
std :: String_view
,则s.substr(0,s.length() - 1)
可以更改为使用s.remove_suffix(1);
。所有这些结合在一起给了您:
要考虑的还有一件事,但这是您算法的完整重写:
您的递归不是尾部递归。这消耗了与字符串长度成比例的堆栈空间。在解析“ int”时,这不是一个问题,这将是更大问题的问题。或者,如果有人进入一个非常大的数字“ 14654645656348756 ... 65464”。
要解决这个问题,您必须扭转算法。与其像迭代性那样从前面切碎数字,将它们从前面带走:
要使此递归您必须将中间结果传递给累积递归。因此,它变成了:
不确定您是如何提出背对面算法的,但是前后会产生更好的代码。
注意:缺少需要C ++ 17,或者如果您愿意,也可以使用
std :: String :: const_iterator
(需要将s.cend()作为额外参数)或良好的旧const char *p = s.c_str();
When you compute the last digit
you have an out-of-bounds access to the string. Changing that to
and your code works. Inefficiently.
You create a new substring in every recursion. There are 2 ways to improve on that:
make a helper function that makes a copy of the string and then calls the recursive function. The recursive function takes a
std::string & s
and then can uses.pop_back()
. As a side benefit the helper function can easily deal with strings starting with '-'. You should have this helper anyway.change the argument to
std::string_view
then it's just a reference into the string and substring will just shrink that reference. The string is never copied. That's actually the only change, just changestd::string
tostd::string_view
and done.I think the
std::string_view
is the way to go but requires c++17. Combine that with the helper for dealing with '-'.The next thing is
s[s.length() - 1]
, which can be written ass.back()
. Safes a bit of typing and no risk of an off-by-one error.Then your condition for terminating the recursion is overly complex. You can write
instead at the cost of an extra recursion call. On the other hand this allows parsing "". Not sure which way is faster, the simpler test might balance the extra recursive call. I like it because it doesn't repeat the digit conversion code and is less to type.
Next, if you are using
std::string_view
, then thes.substr(0, s.length() - 1)
expression can be changed to usings.remove_suffix(1);
.All combined this gives you:
One more thing to consider but it's a complete rewrite of your algorithm:
Your recursion isn't tail recursive. This uses up stack space proportional to the length of the string. While for parsing an "int" this shouldn't be a problem it will be a problem for larger problems. Or if someone just enters a really big number "14654645656348756...65464".
To solve this you have to turn your algorithm around. Instead of chopping digits of at the end take them from the front like you would doing this iteratively:
To make this recursive you have to pass the intermediate result as accumulator down the recursion. So it becomes this:
Not sure how you came up with the back to front algorithm but front to back results in better code.
Note: Short of needing c++17, or if you prefer, you can also use
std::string::const_iterator
(requires passing s.cend() as extra argument) or good oldconst char *p = s.c_str();