[英]Is tail recursion possible if a comparison depends on the return value?
我有一個家庭作業,要求使用直接遞歸的函數來查找數組中最左邊,最低,負整數的索引。 附加要求是函數的參數是數組和大小,無效值的返回值是-999。
我想出了這個:
int LowIndexMinNeg(int src[], int size)
{
if (size == 0)
return -999;
int index = LowIndexMinNeg(src, size - 1);
if (index >= 0)
return (src[size - 1] < src[index]) ? (size - 1) : index;
else
return (src[size - 1] < 0) ? (size - 1) : index;
}
它有效,滿足要求,並得到我充分的信任。 這可以用尾遞歸實現嗎?
在我看來,因為你必須從遞歸調用中獲取結果,以便在比較中使用它來決定你是否通過它或更新它,這是不可能的,但是遞歸仍然會將我的大腦聯系起來可能有一些我很想念的東西。
注意:我的家庭作業已經上交並評分。
如果在返回之前轉換遞歸結果,則不是尾遞歸。
編輯:話雖如此,如果你想使函數tail遞歸:
const int SENTINEL= 0;
int LowIndexMinNeg(int src[], int size, int index)
{
if (size == 0)
{
if (index<0 || src[index]>=0)
return -999;
else
return index;
}
int current_index= size - 1;
int new_index= src[current_index]<=src[index] ? current_index : index;
return LowIndexMinNeg(src, size - 1, new_index);
}
並調用LowIndexMinNeg(src, src_size, src_size - 1)
EDIT2:找到最差的最左邊最負值。 您可以將其作為第一個最負值的索引。
EDIT3:刪除大多數條件,因為它更容易找到最低值的索引,然后檢查它是否為負數。
我可能有提案,但當然我必須更改簽名:
int LowIndexMinNeg(int src[], int size, int min = -999)
{
if (size == 0)
return min;
const int min_value = (min == -999) ? 0 : src[min];
return LowIndexMinNeg(src, size - 1, src[size - 1] <= min_value ? size - 1 : min);
}
以下是使用尾遞歸實現的方法:
int LowIndexMinNeg(int src[], int size, int index = 0, int lowest_index = -999, int lowest_value = 0)
{
if (index >= size) {
return lowest_index;
}
if (src[index] < lowest_value) {
return LowIndexMinNeg(src, size, index+1, index, src[index]);
} else {
return LowIndexMinNeg(src, size, index+1, lowest_index, lowest_value);
}
}
此實現使用默認參數將函數保持在一起,但這會產生一個混亂的接口。 如果您願意,可以將其拆分為兩個函數:
static int LowIndexMinNegHelper(int src[], int size, int index, int lowest_index, int lowest_value)
{
if (index >= size) {
return lowest_index;
}
if (src[index] < lowest_value) {
return LowIndexMinNegHelper(src, size, index+1, index, src[index]);
} else {
return LowIndexMinNegHelper(src, size, index+1, lowest_index, lowest_value);
}
}
int LowIndexMinNeg(int src[], int size)
{
return LowIndexMinNegHelper(src, size, 0, -999, 0);
}
在這種情況下, LowIndexMinNegHelper
只需要是一個本地函數(我在上面用static
表示)。
您需要存儲到目前為止找到的最低數字。 使用您的功能,您可以使用堆棧來存儲它。
使用尾遞歸函數,您需要存儲到目前為止其他地方找到的最小數字。 例如:
您對函數的要求可能會排除所有這些要求,因此您會留下類似於您所擁有的代碼的東西,這些代碼不能被編寫為尾遞歸。
要了解例如最后兩點:
int LowIndexMinNeg(int src[], int size,int current_lowest = 0,int lowest_index = 0) {
if(size == 0)
return current_lowest == 0 ? -999 : lowest_index;
int val = src[size - 1] ;
if(val < 0 && val < current_lowest) {
current_lowest = val;
lowest_index = size -1;
}
return LowIndexMin(src,size - 1,current_lowest,lowest_index);
}
和
struct find_smallest {
int current_lowest = 0;
int lowest_index = 0
int LowIndexMinNeg(int src[], int size) {
if(size == 0)
return current_lowest == 0 ? -999 : lowest_index;
int val = src[size - 1] ;
if(val < 0 && val < current_lowest) {
current_lowest = val;
lowest_index = size - 1;
}
return LowIndexMin(src,size - 1);
}
};
我不確定賦值規則是否允許定義輔助函數,但這是一個標准轉換,用於在操作的最自然簽名不允許時實現尾遞歸。 例如:
int LowIndexMinNeg2(int src[], int size, int min)
{
if (size == 0) return min;
src--; size--;
if (min >= 0) min++;
if (src[0] < 0
&& (min < 0 || src[0] <= src[min]))
min = 0;
return LowIndexMinNeg2(src, size, min);
}
int LowIndexMinNeg2(int src[], int size)
{
return LowIndexMinNeg2(src + size, size, -999);
}
此版本還顛倒了遍歷的順序,使得可以區分“min”的“真實”值和“未找到”值。 其他可能更具可讀性的方法將涉及使用額外的累加器用於實際的最小值(而不是僅僅是索引)和/或當前到數組的偏移量(以便遍歷可以以“正常”順序完成。但是當然,如果我正在編寫類似這樣的東西以供認真使用,我首先不會使用遞歸。
你可以用兩個靜態來做到這一點......
int LowIndexMinNeg(int src[], int size)
{
static int _min = 0;
static int _index = 0;
if (size == 0) return -999;
if (_index == size) return (src[_min] < 0) ? _min : -999;
if (src[_index] < 0 && src[_index] < src[_min]) _min = _index;
++_index;
return LowIndexMinNeg(src, size);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.