警告:a:bash 中使用递归函数的合并排序中的循环名称引用
warning: a: circular name reference in Merge Sort using recursive functions in bash
我正在尝试在 bash 中基于 C 语言实现合并排序,这是我的代码:
#!/bin/bash
function merge() {
local -n a=
local low=
local mid=
local high=
for ((l1 = low, l2 = mid + 1, i = low; l1 <= mid && l2 <= high; i++)); do
if [[ a[$l1] -le a[$l2] ]]; then
b[$i]=${a[((l1++))]}
else
b[$i]=${a[((l2++))]}
fi
done
while [[ $l1 -le $mid ]]; do
b[((i++))]=${a[((l2++))]}
done
while [[ $l2 -le $high ]]; do
b[((i++))]=${a[((l2++))]}
done
for ((i = low; i <= high; i++)); do
a[$i]=${b[$i]}
done
}
function sort() {
local -n a=
local low=
local high=
echo "a=${a[*]}"
echo "low=$low"
echo "high=$high"
if [[ $low < $high ]]; then
mid=$(((low + high) / 2))
sort a "$low" $mid
sort a $((mid + 1)) "$high"
merge a "$low" $mid "$high"
else
echo "${arr[@]}"
fi
}
declare -a arr
echo "Enter the elements of the array: "
read -ra arr
len=${#arr[@]}
echo $len
sort arr 0 $((len - 1))
echo "Array after sort;"
echo "${arr[@]}"
执行后,我收到同样的错误垃圾邮件:
warning: a: circular name reference
完整日志:https://del.dog/error-log.txt
我的解释是,递归函数和 namerefs 在 bash 中并不齐头并进。有什么方法可以在 bash 中实现合并排序?
Namerefs 通过 name 引用变量。因此,这些引用不像 C 中的指针。相反,如果范围发生变化,namerefs 可能会引用一个与预期不同的变量。
这是您的问题的核心。
countdown() {
local -n a=""
if (( a > 0 )); then
echo "$(( a-- ))"
countdown a
fi
}
b=3
countdown b
如果你执行countdown
,你在第一级递归后会得到local -n a=a
。要避免这个问题,只需使用 a
(${!a}
= b
) 引用的全局变量的名称而不是 a
本身进行递归:
countdown() {
local -n a=""
if (( a > 0 )); then
echo "$(( a-- ))"
countdown "${!a}"
fi
}
b=3
countdown b
tl;dr: 调用 sort/merge "${!a}"
而不是 sort/merge a
.
顺便说一句: bash 数组的索引总是一个算术表达式。你可以写 a[i]=...
和 ... "${a[i++]}"
。这里不需要$(( ... )))
。
另外,我想你想写 if (( low < high ))
而不是 if [[ $low < $high
因为 ...
When used with [[, the ‘<’ and ‘>’ operators sort lexicographically using the current locale
... 意思是 29 < 3
.
我正在尝试在 bash 中基于 C 语言实现合并排序,这是我的代码:
#!/bin/bash
function merge() {
local -n a=
local low=
local mid=
local high=
for ((l1 = low, l2 = mid + 1, i = low; l1 <= mid && l2 <= high; i++)); do
if [[ a[$l1] -le a[$l2] ]]; then
b[$i]=${a[((l1++))]}
else
b[$i]=${a[((l2++))]}
fi
done
while [[ $l1 -le $mid ]]; do
b[((i++))]=${a[((l2++))]}
done
while [[ $l2 -le $high ]]; do
b[((i++))]=${a[((l2++))]}
done
for ((i = low; i <= high; i++)); do
a[$i]=${b[$i]}
done
}
function sort() {
local -n a=
local low=
local high=
echo "a=${a[*]}"
echo "low=$low"
echo "high=$high"
if [[ $low < $high ]]; then
mid=$(((low + high) / 2))
sort a "$low" $mid
sort a $((mid + 1)) "$high"
merge a "$low" $mid "$high"
else
echo "${arr[@]}"
fi
}
declare -a arr
echo "Enter the elements of the array: "
read -ra arr
len=${#arr[@]}
echo $len
sort arr 0 $((len - 1))
echo "Array after sort;"
echo "${arr[@]}"
执行后,我收到同样的错误垃圾邮件:
warning: a: circular name reference
完整日志:https://del.dog/error-log.txt
我的解释是,递归函数和 namerefs 在 bash 中并不齐头并进。有什么方法可以在 bash 中实现合并排序?
Namerefs 通过 name 引用变量。因此,这些引用不像 C 中的指针。相反,如果范围发生变化,namerefs 可能会引用一个与预期不同的变量。
这是您的问题的核心。
countdown() {
local -n a=""
if (( a > 0 )); then
echo "$(( a-- ))"
countdown a
fi
}
b=3
countdown b
如果你执行countdown
,你在第一级递归后会得到local -n a=a
。要避免这个问题,只需使用 a
(${!a}
= b
) 引用的全局变量的名称而不是 a
本身进行递归:
countdown() {
local -n a=""
if (( a > 0 )); then
echo "$(( a-- ))"
countdown "${!a}"
fi
}
b=3
countdown b
tl;dr: 调用 sort/merge "${!a}"
而不是 sort/merge a
.
顺便说一句: bash 数组的索引总是一个算术表达式。你可以写 a[i]=...
和 ... "${a[i++]}"
。这里不需要$(( ... )))
。
另外,我想你想写 if (( low < high ))
而不是 if [[ $low < $high
因为 ...
When used with [[, the ‘<’ and ‘>’ operators sort lexicographically using the current locale
... 意思是 29 < 3
.