编程练习:算法与子程序实现

内容分享2天前发布
0 0 0

table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}

63、编写一个名为 is_triangle 的子程序,判断给定的三个棍子长度是否可以组成一个三角形。程序需要提示用户输入三个长度,并对输入进行判断。

以下是相应的代码实现:

首先定义

is_triangle

子程序,它接收三个参数

$x


$y


$z

,初始假设能构成三角形,然后检查是否有一条边大于另外两条边之和,若有则不能构成三角形。

接着提示用户输入三个长度,将输入分割并转换为整数后调用

is_triangle

子程序进行判断。

代码如下:


sub is_triangle (Numeric $x, Numeric $y, Numeric $z) {
    my $valid = True;
    $valid = False if $x > $y + $z;
    $valid = False if $y > $x + $z;
    $valid = False if $z > $x + $y;
    if $valid {
        say "Yes";
    } else {
        say "No";
    }
}

my ($a, $b, $c) = split " ", prompt "Please enter three lengths (separated by spaces): ";
is_triangle $a.Int, $b.Int, $c.Int;

64、编写代码打印前 20 个斐波那契数,以及根据用户输入打印第 n 个斐波那契数。

以下是使用 Python 语言实现的代码:


# 定义函数计算斐波那契数列第 n 项
def fibonacci(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        a, b = 0, 1
        for _ in range(2, n + 1):
            a, b = b, a + b
        return b

# 打印前 20 个斐波那契数
print('前 20 个斐波那契数:')
for i in range(20):
    print(fibonacci(i), end=' ')

# 根据用户输入打印第 n 个斐波那契数
n = int(input('
请输入一个整数 n,将为你输出第 n 个斐波那契数: '))
print(f'第 {n} 个斐波那契数是: {fibonacci(n)}')

上述代码定义了

fibonacci

函数用于计算斐波那契数列的第 n 项,然后使用循环打印前 20 个斐波那契数,最后根据用户输入打印第 n 个斐波那契数。

65、编写一个 compare 子程序,接受两个数字并比较它们,若第一个数字大于第二个则返回 1,若相等则返回 0,否则返回 -1。

以下是满足需求的子程序代码:


sub compare (Numeric $x, Numeric $y) {
    return 1 if $x > $y;
    return 0 if $x == $y;
    return -1;
}

66、使用增量开发计划编写一个 hypotenuse 子程序,计算直角三角形的斜边(使用勾股定理)。

首先编写一个简单的子程序框架:

perl
sub hypotenuse(Numeric $x, Numeric $y) {
return 0;
}
say hypotenuse 3, 4;

此时代码会输出

0

接着在子程序内计算斜边并打印结果:

perl
sub hypotenuse(Numeric $x, Numeric $y) {
my $hypotenuse = sqrt ($x ** 2 + $y ** 2);
say "hypotenuse = $hypotenuse";
return 0.0;
}
say hypotenuse 3, 4;

这时会正确计算出斜边(如

3


4

的斜边为

5

),但仍返回

0

这个占位值。

然后安全地返回计算结果并移除临时打印语句:

perl
sub hypotenuse(Numeric $x, Numeric $y) {
my $hypotenuse = sqrt ($x ** 2 + $y ** 2);
return $hypotenuse;
}
say hypotenuse 3, 4;

此时代码会正确输出斜边的值。

最后,若想进一步简化子程序,可移除临时变量:

perl
sub hypotenuse(Numeric $x, Numeric $y) {
return sqrt ($x ** 2 + $y ** 2);
}
say hypotenuse 3, 4;

67、编写一个子例程来比较两个数字,若第一个数字大于第二个数字则返回 1,若两个数字相等则返回 0,否则返回 -1

以下是实现该功能的代码示例:


sub compare_numbers {
    my ($num1, $num2) = @_;
    if ($num1 > $num2) {
        return 1;
    } elsif ($num1 == $num2) {
        return 0;
    } else {
        return -1;
    }
}

68、编写一个子例程来计算阿克曼函数。阿克曼函数 A(m, n) 定义如下:A(m, n) = n + 1(若 m = 0);A(m – 1, 1)(若 m > 0 且 n = 0);A(m – 1, A(m, n – 1))(若 m > 0 且 n > 0)。此外,修改该子例程以防止传入负参数

以下是计算阿克曼函数的子例程,并修改为防止传入负参数:


sub ack (Int $m where $m >= 0, Int $n where $n >= 0) {
    return $n + 1 if $m == 0;
    return ack($m - 1, 1) if $n == 0;
    return ack($m - 1, ack($m, $n - 1));
}

在这个子例程中,使用了

where

子句来约束参数

$m


$n

必须是非负整数,从而防止传入负参数。

69、编写一个递归子例程,检查一个数是否是另一个数的幂

以下是一个 Perl 6 实现的递归子例程,用于检查一个数是否是另一个数的幂:


sub is_power($num, $base) {
    if $num == 1 {
        return True;
    }
    if $num % $base != 0 {
        return False;
    }
    return is_power($num / $base, $base);
}

你可以使用以下方式调用这个子例程:


# 测试示例
say is_power(8, 2); # 输出 True
say is_power(9, 2); # 输出 False

上述代码定义了一个名为

is_power

的递归子例程,它接受两个参数

$num


$base

,用于检查

$num

是否是

$base

的幂。如果

$num

等于 1,则返回

True

;如果

$num

不能被

$base

整除,则返回

False

;否则,递归调用

is_power

子例程,将

$num

除以

$base

后的结果作为新的

$num

继续检查。

70、编写一个子例程,返回两个数的最大公约数

以下是使用 Python 编写的实现此功能的子例程:


# 定义函数 gcd 用于计算两个数的最大公约数
def gcd(a, b):
    # 当 b 不等于 0 时进行循环
    while b:
        # 将 a 的值赋给 temp
        temp = a
        # 将 b 的值赋给 a
        a = b
        # 将 temp 除以 b 的余数赋给 b
        b = temp % b
    # 返回 a,此时 a 即为最大公约数
    return a

你可以使用以下方式调用这个函数:


# 调用 gcd 函数,传入参数 48 和 18,并将结果存储在 result 变量中
result = gcd(48, 18)
# 打印结果
print(result)  # 输出 6

上述代码中,定义了

gcd

函数,它接受两个参数

a


b

,通过循环不断更新

a


b

的值,直到

b

为 0,此时

a

就是最大公约数。然后调用该函数并传入两个数,将结果存储在

result

变量中并打印出来。

71、编写一个子例程,使用牛顿法通过不断计算更好的近似值来求一个数的平方根

以下是使用 Python 实现的使用牛顿法求一个数平方根的子例程:


def sqrt_newton(n, tolerance=1e-10):
    if n < 0:
        raise ValueError("不能对负数求平方根")
    if n == 0:
        return 0
    guess = n / 2
    while True:
        better_guess = (guess + n / guess) / 2
        if abs(better_guess - guess) < tolerance:
            break
        guess = better_guess
    return guess

你可以调用这个函数,例如

sqrt_newton(9)

来计算 9 的平方根。

72、我们需要一个子程序,使用牛顿法通过不断计算更优的根近似值来求一个数的平方根。选择10⁻¹¹(即1e – 11)作为epsilon的值,使用$a/2作为$a的初始估计值。请实现用于计算一个数平方根的牛顿法。

以下是实现代码:


sub my_sqrt ($a) {
    my $epsilon = 1e - 11;
    my $estimate = $a / 2;
    while (1) {
        # say "-- Intermediate value: $estimate";
        my $y = ($estimate + $a/$estimate) / 2;
        last if abs($y - $estimate) < $epsilon;
        $estimate = $y;
    }
    return $estimate;
}

73、根据斯里尼瓦瑟·拉马努金(Srinivasa Ramanujan)的算法估算圆周率。实现一个子程序,使用拉马努金算法来估算圆周率。

以下是使用拉马努金算法估算圆周率的子程序实现:


sub factorial(Int $n) {
    return 1 if $n == 0;
    return $n * factorial($n - 1);
}

sub estimate-pi {
    my $factor = 2 * sqrt(2) / 9801;
    my $k = 0;
    my $sum = 0;
    while (1) {
        my $num = factorial(4 * $k) * (1103 + 26390 * $k);
        my $den = factorial($k)**4 * 396**(4 * $k);
        my $term = $factor * $num / $den;
        last if abs($term) < 1e-15;
        $sum += $term;
        $k++;
    }
    return 1 / $sum;
}

你可以调用

estimate-pi

子程序来获取圆周率的估算值。

74、使用while循环对一个单词进行反向遍历。

以下是两种实现方式:

方式一:


my $fruit = "banana";
my $index = $fruit.chars;
while ($index > 0) {
    $index--;
    my $letter = substr($fruit, $index, 1);
    say $letter;
}

方式二:


my $fruit = "banana";
my $index = $fruit.chars;
while ($index > 0) {
    say substr($fruit, --$index, 1);
}

75、如何生成小鸭子名字(以 ‘ack’ 为后缀,前缀为 ‘J’ 到 ‘N’、’Ou’、’P’、’Qu’)的列表?

可以通过遍历给定的前缀,将它们与

'ack'

后缀组合来生成小鸭子名字列表。以下是示例代码:


my @prefixes = ('J', 'K', 'L', 'M', 'N', 'Ou', 'P', 'Qu');
my @duck_names;
foreach my $prefix (@prefixes) {
    push @duck_names, $prefix . 'ack';
}
foreach my $name (@duck_names) {
    say $name;
}

运行上述代码,即可得到以

'ack'

为后缀,前缀为

'J'


'N'


'Ou'


'P'


'Qu'

的小鸭子名字列表。

76、编写一个子程序,用于计算一个单词(或任何字符串)中特定字母的出现次数。

可以使用以下 Perl 6 代码实现该子程序:


sub count_letter(Str $word, Str $letter) {
    return $word.comb.grep(* eq $letter).elems;
}

示例调用


my $word = "hello";
my $letter = "l";
say count_letter($word, $letter);

上述代码定义了一个名为

count_letter

的子程序,它接受一个字符串

$word

和一个字母

$letter

作为参数。在子程序内部,首先使用

comb

方法将字符串拆分为单个字符,然后使用

grep

方法筛选出与指定字母相等的字符,最后使用

elems

方法计算筛选结果的元素个数,即特定字母的出现次数。

77、如何找到句子中以字母 ‘a’ 开头的第一个单词?

可以使用以下代码:


my $string = "Four scores and seven years ago our fathers ...";
say ~$0 if $string ~~ /W (a w+)/;

运行后会输出以字母 ‘a’ 开头的第一个单词。

78、如何在字符串中找到重复的字母?

可以通过遍历字符串并统计每个字母出现的次数来找到重复字母。示例代码如下:


my $string = "Eastern Tennessee anteaters ensnare and eat red ants, detest ant antennae (a tart taste) and dread Antarean anteater - eaters. Rare Andean deer eat tender sea reeds, aster seeds and rats’ ears. Dessert? Rats’ asses.";
my %frequencies;
%frequencies{$_}++ for grep { /w/ }, $string.lc.comb;

这里将字符串字母转为小写,仅考虑字母,忽略空格和标点,最后统计字母出现次数,出现次数大于 1 的字母即为重复字母。

若要考虑标点,原代码修改部分有误,正确的做法可以直接遍历所有字符进行统计,代码可改为:


%frequencies{$_}++ for $string.lc.comb;

79、修正 is – reverse 子程序中的第二个错误,该子程序用于判断两个字符串是否互为反转。

原代码中

while $j > 0

存在问题,为了将

$word2

的第一个字母与

$word1

的最后一个字母进行比较,

$j

索引应允许向下循环到

0

(包含

0

)。修正后的代码如下:


sub is-reverse(Str $word1, Str $word2) {
    return False if $word1.chars != $word2.chars;
    my $i = 0;
    my $j = $word2.chars - 1;
    while $j >= 0 {
        return False if substr($word1, $i, 1) ne substr($word2, $j, 1);
        $i++;
        $j--;
    }
    return True;
}

80、分析 any_lowercase1 到 any_lowercase9 这几个子程序,找出哪些子程序能正确检查输入字符串是否至少包含一个小写字母,并找出其他子程序的错误。

能正确检查输入字符串是否至少包含一个小写字母的子程序是

any_lowercase5


any_lowercase7

。其他子程序的错误如下:

any_lowercase1

:只检查参数的第一个字符,然后退出循环;

any_lowercase2

:调用

is-lower

子程序时使用的是字符串

"char"

,而非

$char

变量,且和

any_lowercase1

有相同缺陷;

any_lowercase3

:仅根据输入字符串的最后一个字符返回

True


False

any_lowercase4

:存在运算符优先级问题,赋值操作先于

or

运算符执行;

any_lowercase6

:算法基本正确,但返回的是字符串

"True"


"False"

,而非布尔值;

any_lowercase8


any_lowercase9

:若有任何字符不是小写字母就返回

False

81、实现一个字母旋转密码,编写 rotate – one – letter、rotate – one – word 和 rot13 子程序,并添加大写字母的范围作为进一步练习。

以下是实现字母旋转密码的代码:


sub rotate-one-letter (Str $letter, Int $shift) {
    my $upper-end = 'Z'.ord; # 最后一个大写字母
    my $lower-end = 'z'.ord; # 最后一个小写字母
    my $rotated-ord = $letter.ord + $shift;
    if $letter ~~ /<[a..z]>/ { # 小写字母
        $rotated-ord -= 26 if $rotated-ord > $lower-end;
    } elsif $letter ~~ /<[A..Z]>/ { # 大写字母
        $rotated-ord -= 26 if $rotated-ord > $upper-end;
    } else {
        return $letter;
    }
    return $rotated-ord.chr;
}
sub rotate-one-word (Str $word, Int $shift is copy) {
    $shift = $shift % 26;
    $shift = 26 + $shift if $shift < 0;
    my $rotated-word = "";
    for 0..$word.chars - 1 {
        $rotated-word ~= rotate-one-letter substr($word, $_, 1), $shift;
    }
    return $rotated-word;
}
sub rot13 (Str $word) {
    return rotate-one-word $word, 13;
}

进一步添加大写字母范围的示例(使用

tr

操作符):


$ perl6 -e 'my $w = "Foobar"; $w ~~ tr/a..mn..zA..MN..Z/n..za..mN..ZA..M/; say $w;'

82、编写程序,使用类似 index 函数的方法计算一个单词中字母“a”的数量

以下是一个Python示例程序来实现此功能:


word = "example"
count = 0
index = 0
while True:
    index = word.find('a', index)
    if index == -1:
        break
    count = count + 1
    index = index + 1
print(count)

在这个程序中,使用

find

函数(可类比于index函数)来查找字母“a”的位置,通过循环不断查找直到找不到为止,同时记录找到的次数。将

word

变量的值替换为你想要计算的单词即可。

83、编写程序迭代 15 到 75 之间的可能年龄差,为每个年龄差计算所有回文可能性,包括计算每种年龄差的回文实例数量以及打印女儿和母亲年龄的回文组合

以下是一个 Python 程序示例,用于实现迭代 15 到 75 之间的可能年龄差,计算每种年龄差下的回文可能性、回文实例数量,并打印女儿和母亲年龄的回文组合:


for age_difference in range(15, 76):
    palindrome_count = 0
    print(f"年龄差为 {age_difference} 时的回文组合:")
    for daughter_age in range(1, 100):
        mother_age = daughter_age + age_difference
        if str(daughter_age) == str(daughter_age)[::-1] and str(mother_age) == str(mother_age)[::-1]:
            print(f"女儿年龄: {daughter_age}, 母亲年龄: {mother_age}")
            palindrome_count += 1
    print(f"年龄差为 {age_difference} 时的回文实例数量: {palindrome_count}")
    print()

这个程序会遍历 15 到 75 之间的每个年龄差,对于每个年龄差,会遍历女儿可能的年龄,计算母亲的年龄,并检查女儿和母亲的年龄是否都是回文数。如果是,则打印出这个组合,并增加回文实例的计数。最后,打印出该年龄差下的回文实例数量。

© 版权声明

相关文章

暂无评论

none
暂无评论...