函数基础

一个典型的函数定义包括以下部分:修饰符、返回类型、函数名字、由0个或多个形参组成的列表以及函数体。

编写函数

1
2
3
4
5
6
7
8
9
10
public class Main
{
private static int fact(int val)
{
int res = 1;
for (int i = 1; i <= val; i ++)
res *= i;
return res;
}
}

函数名字是fact,它作用于一个整型参数,返回一个整型值。return语句负责结束fact并返回res的值。
修饰符包括privatestatic等,它们属于类相关的概念,会在下一章解释。

调用函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.Scanner;

public class Main
{
private static int fact(int val)
{
int res = 1;
for (int i = 1; i <= val; i ++)
res *= i;
return res;
}

public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int res = fact(a);
System.out.printf("%d! is %d", a, res);
}
}

输入

1
5

输出

1
120

函数的调用完成两项工作:一是用实参初始化函数对应的形参,二是将控制权转移给被调用函数。此时,主调函数的执行被暂时中断,被调函数开始执行。

形参和实参

实参是形参的初始值。第一个实参初始化第一个形参,第二个实参初始化第二个形参,依次类推。形参和实参的类型和个数必须匹配。

1
2
3
4
fact("hello");      // 错误:实参类型不正确
fact(); // 错误:实参数量不足
fact(42, 10, 0); // 错误:实参数量过多
fact(' '); // 正确:该实参能自动转换成int类型,' '的ASCII值为32,所以该操作等价于fact(32);

函数的形参列表

函数的形参列表可以为空,但是不能省略。

1
void f1() {/* …. */}            // 空形参列表

形参列表中的形参通常用逗号隔开,其中每个形参都是含有一个声明符的声明。即使两个形参的类型一样,也必须把两个类型都写出来:

1
2
int f3(int v1, v2) {/* … */}        // 错误
int f4(int v1, int v2) {/* … */} // 正确

函数的返回类型

大多数类型都能用作函数的返回类型。一种特殊的返回类型是void,它表示函数不返回任何值。
函数的返回类型也可以是数组、字符串或者其他对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.Arrays;

public class Main {
public static int[] newArray() {
int[] a = {1, 2, 3};
return a;
}

public static String newString() {
return "Hello World";
}

public static void main(String[] args) {
System.out.println(Arrays.toString(newArray()));
System.out.println(newString());
}
}

输出

1
2
[1, 2, 3]
Hello World

变量的作用域

函数内定义的变量为局部变量,只能在函数内部使用。

定义在类中的变量为成员变量,可以在类的所有成员函数中调用。

当局部变量与全局变量重名时,会优先使用局部变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Main {
private static int x = 4;

private static void f1() {
int x = 3;
System.out.println(x);
}

private static void f2() {
System.out.println(x);
}

private static void f3() {
System.out.println(x + 1);
}

public static void main(String[] args) {
f1();
f2();
f3();
}
}

输出

1
2
3
3
4
5

参数传递

值传递

八大基本数据类型和String类型等采用值传递。

将实参的初始值拷贝给形参。此时,对形参的改动不会影响实参的初始值。

1
2
3
4
5
6
7
8
9
10
11
public class Main {
public static void f(int x) {
x = 5;
}

public static void main(String[] args) {
int x = 10;
f(x);
System.out.println(x);
}
}

输出

1
10

引用传递

String以外的数据类型的对象,例如数组、StringBuilder等采用引用传递。

将实参的引用(地址)传给形参,通过引用找到变量的真正地址,然后对地址中的值修改。所以此时对形参的修改会影响实参的初始值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.Arrays;

public class Main {
public static void f1(int[] a) {
for (int i = 0, j = a.length - 1; i < j; i ++, j --) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}

public static void f2(StringBuilder sb) {
sb.append("Hello World");
}

public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5};
f1(a);
System.out.println(Arrays.toString(a));

StringBuilder sb = new StringBuilder("");
f2(sb);
System.out.println(sb);
}
}

输出

1
2
[5, 4, 3, 2, 1]
Hello World

返回类型和return语句

return语句终止当前正在执行的函数并将控制权返回到调用该函数的地方。return语句有两种形式:

1
2
return;
return expression;

无返回值函数

没有返回值的return语句只能用在返回类型是void的函数中。返回void的函数不要求非得有return语句,因为在这类函数的最后一句后面会隐式地执行return

通常情况下,void函数如果想在它的中间位置提前退出,可以使用return语句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main {
private static void swap(int[] a) {
if (a[0] == a[1])
return;

int tmp = a[0];
a[0] = a[1];
a[1] = tmp;
}

public static void main(String[] args) {
int[] a = {3, 4};
swap(a);
System.out.printf("%d %d", a[0], a[1]);
}
}

输出

1
4 3

有返回值的函数

只要函数的返回类型不是void,则该函数内的每个分支都必须有return语句,且每条return语句都必须返回一个值。return语句返回值的类型必须与函数的返回类型相同,或者能隐式地转换函数的返回类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.Scanner;

public class Main {
private static int max(int a, int b) {
if (a > b)
return a;
else
return b;
}

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
System.out.println(max(a, b));
}
}

输入

1
3 4 

输出

1
4

函数重载

函数重载是指在同一个类中存在多个函数,函数名称相同但参数列表不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.Scanner;

public class Main {
private static int max(int a, int b) {
System.out.println("int max");
if (a > b) return a;
return b;
}

private static double max(double a, double b) {
System.out.println("double max");
if (a > b) return a;
return b;
}

public static void main(String[] args) {
System.out.println(max(3, 4));
System.out.println(max(3.0, 4.0));
}
}

输出

1
2
3
4
int max
4
double max
4.0

函数递归

在一个函数内部,也可以调用函数本身。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//求斐波那契数列的第n项
import java.util.Scanner;

public class Main {
private static int fib(int n) {
if (n <= 2)
return 1;
else
return fib(n - 1) + fib(n - 2);
}

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
System.out.println(fib(a));
}
}

输入

1
6

输出

1
8

例题

  1. n的阶乘

    输入一个整数 n,请你编写一个函数,int fact(int n),计算并输出 n 的阶乘

    输入格式

    共一行,包含一个整数 n。

    输出格式

    共一行,包含一个整数表示 n 的阶乘的值。

    输入样例

    1
    3

    输出样例

    1
    6

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import java.util.Scanner;

    public class Main {
    private static int fact(int n) {
    int ans = 1;
    for (int i = 1; i <= n ;i ++)
    ans *= i;
    return ans;
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    System.out.print(fact(n));
    }
    }
  2. x和y的最大值

    输入两个整数 x 和 y,请你编写一个函数,int max(int x, int y),计算并输出 x 和 y 的最大值。

    输入格式

    共一行,包含两个整数 x 和 y。

    输出格式

    共一行,包含一个整数,表示两个数中较大的那个数。

    输入样例

    1
    3 6

    输出样例

    1
    6

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import java.util.Scanner;

    public class Main {
    private static int max(int x, int y) {
    if (x > y)
    return x;
    else
    return y;
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int x = sc.nextInt();
    int y = sc.nextInt();
    System.out.println(max(x, y));
    }
    }
  3. 最大公约数

    输入两个整数 a 和 b,请你编写一个函数,int gcd(int a, int b), 计算并输出 a 和 b 的最大公约数。

    输入格式

    共一行,包含两个整数 a 和 b。

    输出格式

    共一行,包含一个整数,表示 a 和 b 的最大公约数。

    输入样例

    1
    12 16

    输出样例

    1
    4

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import java.util.Scanner;

    public class Main {
    private static int gcd(int a, int b) {
    if (a > b) {
    int tmp = a;
    a = b;
    b = tmp;
    }

    for (int i = a; i >= 1; i --)
    if ((a % i == 0) && (b % i == 0))
    return i;

    return 1;
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int x = sc.nextInt();
    int y = sc.nextInt();
    System.out.println(gcd(x, y));
    }
    }
  4. 交换数值

    输入两个整数 x 和 y,请你编写一个函数, 交换两个整数的数值并输出交换后的 x 和 y。

    格式为:void swap(int &x, int &y)

    输入格式

    共一行,包含两个整数 x 和 y。

    输出格式

    共一行,包含交换后的 x 和 y。

    输入样例

    1
    3 5

    输出样例

    1
    5 3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import java.util.Scanner;

    public class Main {
    private static void swap(int[] a) {
    int tmp = a[0];
    a[0] = a[1];
    a[1] = tmp;
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int[] a = new int[2];
    a[0] = sc.nextInt();
    a[1] = sc.nextInt();
    swap(a);
    System.out.printf("%d %d", a[0], a[1]);
    }
    }
  5. 打印数字

    输入一个长度为 n 的数组 a 和一个整数 size,请你编写一个函数, void print(int a[], int size), 打印数组 a 中的前 size 个数。

    输入格式

    第一行包含两个整数 n 和 size。

    第二行包含 n 个整数 a[i],表示整个数组。

    输出格式

    共一行,包含 size 个整数,表示数组的前 size 个数。

    输入样例

    1
    2
    5 3
    1 2 3 4 5

    输出样例

    1
    1 2 3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import java.util.Scanner;

    public class Main {
    private static void print(int a[], int size) {
    for (int i = 0; i < size; i ++)
    System.out.printf("%d ", a[i]);
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int size = sc.nextInt();
    int[] a = new int[n];
    for (int i = 0; i < n; i ++)
    a[i] = sc.nextInt();
    print(a, size);
    }
    }
  6. 打印矩阵

    给定一个 row×col 的二维数组 a,请你编写一个函数,void print2D(int a[][N], int row, int col),打印数组构成的 row 行,col 列的矩阵。

    注意,每打印完一整行需要输出一个回车。

    输入格式

    第一行包含两个整数 row,col

    接下来 row 行,每行包含 col 个整数,表示完整二维数组a

    输出格式

    row 行,每行 col 个整数,表示打印出的矩阵。

    输入样例

    1
    2
    3
    4
    3 4
    1 3 4 5
    2 6 9 4
    1 4 7 5

    输出样例

    1
    2
    3
    1 3 4 5
    2 6 9 4
    1 4 7 5

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import java.util.Scanner;

    public class Main {
    private static void print2D(int a[][], int row, int col) {
    for (int i = 0; i < row; i ++) {
    for (int j = 0; j < col; j ++)
    System.out.printf("%d ", a[i][j]);
    System.out.println();
    }

    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int r = sc.nextInt();
    int c = sc.nextInt();
    int[][] a = new int[r][c];
    for (int i = 0; i < r; i ++)
    for (int j = 0; j < c; j ++)
    a[i][j] = sc.nextInt();
    print2D(a, r, c);
    }
    }
  7. 递归求阶乘

    请使用递归的方式求 n 的阶乘。

    输入格式

    共一行,包含一个整数 n。

    输出格式

    共一行,包含一个整数,表示 n 的阶乘的值。

    输入样例

    1
    3

    输出样例

    1
    6

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import java.util.Scanner;

    public class Main {
    private static int fact(int n) {
    if (n == 1)
    return 1;
    else
    return n * fact(n - 1);
    }
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    System.out.println(fact(n));
    }
    }
  8. 递归求斐波那契数列

    请使用递归的方式求斐波那契数列的第 n 项,下标从1开始。

    斐波那契数列:1,1,2,3,5…,这个数列从第 3 项开始,每一项都等于前两项之和

    输入格式

    共一行,包含整数 n。

    输出格式

    共一行,包含一个整数,表示斐波那契数列的第 n 项。

    输入样例

    1
    4

    输出样例

    1
    3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import java.util.Scanner;

    public class Main {
    private static int fib(int n) {
    if (n <= 2) return 1;
    else return fib(n - 1) + fib(n - 2);
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    System.out.println(fib(n));
    }
    }

习题

  1. 绝对值

    输入一个整数 x,请你编写一个函数,int abs(int x),输出 x 的绝对值。

    输入格式

    共一行,包含一个整数 x。

    输出格式

    共一行,包含 x 的绝对值。

    输入样例

    1
    -3

    输出样例

    1
    3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import java.util.Scanner;

    public class Main {
    private static int abs(int x) {
    if (x >= 0) return x;
    else return -x;
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int x = sc.nextInt();
    System.out.println(abs(x));
    }
    }
  2. 两个数的和

    输入两个浮点数 x 和 y,请你编写一个函数,double add(double x, double y),计算并输出 x 与 y 的和。

    输入格式

    共一行,包含两个浮点数 x 和 y。

    输出格式

    共一行,包含一个浮点数,表示两个数的和,结果保留 2 位小数。

    输入样例

    1
    1.11 2.22

    输出样例

    1
    3.33

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import java.util.Scanner;

    public class Main {
    private static double add(double x, double y) {
    return x + y;
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    double x = sc.nextDouble();
    double y = sc.nextDouble();
    System.out.printf("%.2f", add(x, y));
    }
    }
  3. 区间求和

    输入两个整数 l 和 r,请你编写一个函数,int sum(int l, int r),计算并输出区间 [l,r] 内所有整数的和。

    输入格式

    共一行,包含两个整数 l 和 r。

    输出格式

    共一行,包含一个整数,表示所求的和。

    输入样例

    1
    3 5

    输出样例

    1
    12

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import java.util.Scanner;

    public class Main {
    private static int sum(int l, int r) {
    int s = 0;
    for (int i = l; i <= r; i ++)
    s += i;
    return s;
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int x = sc.nextInt();
    int y = sc.nextInt();
    System.out.println(sum(x, y));
    }
    }
  4. 最小公倍数

    输入两个整数 a 和 b,请你编写一个函数,int lcm(int a, int b),计算并输出 a 和 b 的最小公倍数。

    输入格式

    共一行,包含两个整数 a 和 b。

    输出格式

    共一行,包含一个整数,表示 a 和 b 的最小公倍数。

    输入样例

    1
    6 8

    输出样例

    1
    24

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import java.util.Scanner;

    public class Main {
    private static int lcm(int a, int b) {
    if (a < b) {
    int tmp = a;
    a = b;
    b = tmp;
    }

    for (int i = a; i < a * b; i ++)
    if ((i % a == 0) && (i % b == 0))
    return i;

    return a * b;
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int a = sc.nextInt();
    int b = sc.nextInt();
    System.out.println(lcm(a, b));
    }
    }
  5. 复制数组

    给定两个数组 a 和 b 以及一个整数 size,请你编写一个函数,void copy(int a[], int b[], int size),将 a 数组中的前 size 个数字,复制到 b 数组中。

    复制完成后,输出 b 数组。

    输入格式

    第一行包含整数 n,m,size,分别表示 a 数组的长度,b 数组的长度以及整数 size。

    第二行包含 n 个整数,表示数组 a。

    第三行包含 m 个整数,表示数组 b。

    输出格式

    共一行,包含 m 个整数,表示复制完成后的数组 b。

    输入样例

    1
    2
    3
    3 5 2
    1 2 3
    4 5 6 7 8

    输出样例

    1
    1 2 6 7 8

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import java.util.Scanner;

    public class Main {
    private static void copy(int a[], int b[], int size) {
    for (int i = 0; i < size; i ++)
    b[i] = a[i];
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int m = sc.nextInt();
    int size = sc.nextInt();
    int[] a = new int[n];
    int[] b = new int[m];
    for (int i = 0; i < n; i ++)
    a[i] = sc.nextInt();
    for (int i = 0; i < m; i ++)
    b[i] = sc.nextInt();
    copy(a, b, size);
    for (int i = 0; i < m; i ++)
    System.out.printf("%d ", b[i]);
    }
    }
  6. 打印字符串

    给定一个字符串,请你编写一个函数,void print(char str[]),将这个字符串打印出来。

    输入格式

    共一行,包含一个字符串。

    输出格式

    共一行,表示打印出的字符串。

    输入样例

    1
    Darling in the Franxx.

    输出样例

    1
    Darling in the Franxx.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import java.util.Scanner;
    import java.util.Arrays;

    public class Main {
    private static void print(char str[]) {
    System.out.println(str);
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    String str = sc.nextLine();
    char[] strs = str.toCharArray();
    print(strs);
    }
    }
  7. 数组翻转

    给定一个长度为 n 的数组 a 和一个整数 size,请你编写一个函数,void reverse(int a[], int size),实现将数组 a 中的前 size 个数翻转。

    输出翻转后的数组 a。

    输入格式

    第一行包含两个整数 n 和 size。

    第二行包含 n 个整数,表示数组 a。

    输出格式

    共一行,包含 n 个整数,表示翻转后的数组 a。

    输入样例

    1
    2
    5 3
    1 2 3 4 5

    输出样例

    1
    3 2 1 4 5

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import java.util.Scanner;
    import java.util.Arrays;

    public class Main {
    private static void reverse(int a[], int size) {
    for (int i = 0, j = size - 1; i < j; i ++, j --) {
    int tmp = a[i];
    a[i] = a[j];
    a[j] = tmp;
    }
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int size = sc.nextInt();
    int[] a = new int[n];
    for (int i = 0; i < n; i ++)
    a[i] = sc.nextInt();
    reverse(a, size);
    for (int i = 0; i < n; i ++)
    System.out.printf("%d ", a[i]);
    }
    }
  8. 数组去重

    给定一个长度为 n 的数组 a,请你编写一个函数:int get_unique_count(int a[], int n),返回数组前n个数中的不同数的个数

    输入格式

    第一行包含一个整数 n。

    第二行包含 n 个整数,表示数组 a。

    输出格式

    共一行,包含一个整数表示数组中不同数的个数。

    输入样例

    1
    2
    5
    1 1 2 4 5

    输出样例

    1
    4

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import java.util.Scanner;

    public class Main {
    private static int get_unique_count(int a[], int n) {
    int cnt = 0;
    int[] s = new int[1001];
    for (int i = 0; i < n; i ++)
    s[a[i]] ++;

    for (int i = 0; i < 1001; i ++)
    if (s[i] != 0)
    cnt ++;
    return cnt;
    }

    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int[] a = new int[n];
    for (int i = 0; i < n; i ++)
    a[i] = sc.nextInt();
    System.out.println(get_unique_count(a, n));
    }
    }
  9. 数组排序

    给定一个长度为 n 的数组 a 以及两个整数 l 和 r,请你编写一个函数,void sort(int a[], int l, int r),将 a[l]∼a[r] 从小到大排序。

    输出排好序的数组 a。

    输入格式

    第一行包含三个整数 n,l,r。

    第二行包含 n 个整数,表示数组 a。
    输出格式

    共一行,包含 n 个整数,表示排序完成后的数组 a。

    输入样例

    1
    2
    5 2 4
    4 5 1 3 2

    输出样例

    1
    4 5 1 2 3