【Day07-集合-Map&Stream&递归】

        可变参数

        就是一种特殊形参,定义在方法、构造器的形参列表里,定义格式是:方法名(数据类型...  形参名称){  }        

         可变参数的特点和好处

  • 特点:可以传数据给它;可以传一个或者同时传多个数据给它;也可以传一个数组给它。
  • 好处:常常用来灵活的接收数据。

        可变参数的注意事项:

  • 可变参数在方法内部就是一个数组
  • 一个形参列表中可变参数只能有一个
  • 可变参数必须放在形参列表的最后面
    /*
    可变参数
        就是一种特殊形参,定义在方法、构造器的形参列表里,格式是:数据类型... 参数名称
    
    优点
        特点:可以不传数据给它;可以传一个或者同时传多个数据给它;也可以传一个数组给它。
        好处:常常用来灵活的接收数据。
    
    注意事项
        1. 可变参数在方法内部就是一个数组
        2. 一个形参列表中可变参数只能有一个
        3. 可变参数必须放在形参列表的最后面
    */
    public class Demo {
    
        public static void main(String[] args) {
            System.out.println(sum(1, 2, 3, 4, 5, 7, 9, 8, 6));
    
        }
    
        //计算2个整数的和
    
        //计算3个整数的和
    
        //计算4个整数的和
    	
    	//计算n个整数的和
        public static int sum(int... nums) {
            int sum = 0;
            for (int num : nums) {
                sum += num;
            }
            return sum;
        }
    }
    

         Collections

        是一个用来操作集合工具类

        Collections提供的常用静态方法

方法名称

说明

public static <T> boolean addAll(Collection<? super T> c, T... elements)

给集合批量添加元素

public static void shuffle(List<?> list)

打乱List集合中的元素顺序

public static <T> void sort(List<T> list)

List集合中元素进行升序排序

public static <T> void sort(List<T> list,Comparator<? super T> c)

List集合中元素按照比较器对象指定的规则进行排序

/*
Collections
    这是一个用于操作单列集合的工具类
    注意跟Collection的区别(Collection是单列集合的根接口)

常用方法
    static <T> boolean addAll(单列集合,可变参数)   批量添加元素
    static void shuffle(List集合)    打乱List集合元素顺序,每次调用都会打乱
    static <T> void sort(List集合)   List集合进行自然排序
    static <T> void sort(List集合,比较器)  List集合进行比较器排序
*/
public class Demo {
    public static void main(String[] args) {
        //static <T> boolean addAll(单列集合,可变参数)   批量添加元素
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "悟空", "红孩儿", "牛魔王", "奥特曼");
        System.out.println(list);
        System.out.println("----------------------------------");
        //static void shuffle(List集合)    打乱List集合元素顺序,每次调用都会打乱
        Collections.shuffle(list);
        System.out.println(list);
        System.out.println("----------------------------------");
        //static <T> void  sort(List集合)   List集合进行自然排序
        List<Integer> nums = new ArrayList<>();
        Collections.addAll(nums, 9, 2, 7, 22, 8);
        Collections.sort(nums);
        System.out.println(nums);
        System.out.println("----------------------------------");
        //排自定义类对象,需要指定排序规则
        List<Student> stuList = new ArrayList<>();
        stuList.add(new Student("zhangsan", 18));
        stuList.add(new Student("wangwu", 22));
        stuList.add(new Student("zhaoliu", 21));
        stuList.add(new Student("lisi", 19));
        stuList.add(new Student("qianqi", 20));

        //static<T> void sort(List集合,比较器);List集合进行比较器排序
        Collections.sort(stuList, (o1, o2) -> o1.getAge() - o2.getAge());
    }
}


class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Map集合

        认识Map集合

  • Map集合称为双列集合一次需要存一对数据做为一个元素, 格式:{key1=value1 , key2=value2 , key3=value3 , ...}
  • Map集合的每个元素分为两部分:keyvaluekey称为键,value称为值,整体叫键值对,因此Map也叫“键值对集合
  • Map集合的所有键是不允许重复的,但值可以重复,键和值是一一对应的,每一个键只能找到自己对应的值

        Map集合在什么业务场景下使用 

         Map集合体系

         Map集合体系的特点

 注意:Map系列集合的特点都是由键决定的,值只是一个附属品,值是不做要求的

  • HashMap: 无序、不重复  (用的最多)
  • LinkedHashMap有序、不重复
  • TreeMap: 按照大小默认升序排序不重复 

        1、Map集合是什么?什么时候可以考虑使用Map集合?

                Map集合是键值对集合

                需要存储一一对应的数据时,就可以考虑使用Map集合来做

        2、Map集合的实现类有哪些?各自的特点是?

                HashMap: 无序,不重复

                LinkedHashMap: 有序,不重复

                TreeMap:排序,不重复

常用方法

        为什么要先学习Map的常用方法 ?

        Map是双列集合的祖宗,它的功能是全部双列集合都可以继承过来使用的。

        Map的常用方法如下:

方法名称

说明

public V put(K key,V value)

添加/修改元素

public int size()

获取集合的大小

public void clear()

清空集合

public boolean isEmpty()

判断集合是否为空

public V get(Object key)

根据键获取对应值

public V remove(Object key)

根据键删除整个元素

public boolean containsKey(Object key)

判断是否包含某个键

public boolean containsValue(Object value)

判断是否包含某个值

public Set<K> keySet()

获取全部键的集合

public Collection<V> values()

获取Map集合的全部值

/*
Map
    双列集合根接口,它的功能是全部双列集合都可以继承过来使用的。

常用方法
    V put(K key,V value)   添加元素
    int size()	获取集合的大小
    boolean isEmpty()	判断集合是否为空,为空返回true, 反之
    V get(Object key)	根据键获取对应值
    V remove(Object key)	根据键删除整个元素
    boolean containsKey(Object key)	  判断是否包含某个键
    boolean containsValue(Object value)	  判断是否包含某个值
    Set<K> keySet()	 获取全部键的集合
    Collection<V> values()	 获取Map集合的全部值
    void clear()	清空集合
*/
public class Demo1 {
    public static void main(String[] args) {
        //使用多态创建一个HashMap
        Map<String, String> map = new HashMap<>();
        //向map中存入西游四人组的编号和姓名 001-玄奘  002-悟空  003-悟能  004-悟净
        //V put(K key,V value)   添加元素
        map.put("001", "悟空");
        map.put("002", "玄奘");
        map.put("003", "悟能");
        map.put("004", "悟净");
        //int size()	获取集合的大小
        System.out.println(map.size());
        //boolean isEmpty()	判断集合是否为空,为空返回true, 反之
        System.out.println(map.isEmpty());
        //V get(Object key)	根据键获取对应值
        String str = map.get("002");
        System.out.println(str);
        //V remove(Object key)	根据键删除整个元素
        map.remove("003");
        System.out.println(map);
        //boolean containsKey(Object key)	  判断是否包含某个键
        boolean result = map.containsKey("001");
        System.out.println(result);
        //boolean containsValue(Object value)	  判断是否包含某个值
        boolean containsValue = map.containsKey("悟能");
        System.out.println(containsValue);
        //Set<K> keySet()	 获取全部键的集合
        Set<String> keys= map.keySet();
        System.out.println(keys);
        //Collection<V> values()	 获取Map集合的全部值
        Collection<String> values = map.values();
        System.out.println(values);
        //void clear()	清空集合
        map.clear();
        System.out.println(map);
    }
}

        Map集合的遍历方式一

先获取Map集合全部的键,再通过遍历键找值

方法名称

说明

public Set<K> keySet()

获取所有键的集合

public V get(Object key)

根据键获取其对应的值

        Map集合的遍历方式二 

把“键值对看成一个整体进行遍历

         Map集合的遍历方式三

需要用到Map的如下方法

方法名称

说明

default void forEach(BiConsumer<? super K, ? super V> action)

结合lambda遍历Map集合

public class Demo2 {
    public static void main(String[] args) {
        //1. 创建map
        HashMap<String, String> map = new HashMap<>();
        map.put("001", "河北");
        map.put("002", "山东");
        map.put("003", "山西");
        map.put("004", "河南");
        //2. 各种方式进行遍历
        test1(map);
        test2(map);
        test3(map);
    }

    //遍历方式1: 先获取Map集合全部的键,再通过遍历键来找值
    private static void test1(HashMap<String, String> map) {
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(key + "---" + map.get(key));
        }
    }

    //遍历方式2: 将map中的所有键值对放入一个set集合中, 然后遍历set集合拿到每个键值对, 再取里面的键值
    private static void test2(HashMap<String, String> map) {
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "---" + value);
        }
    }

    //遍历方式3: Lambda, 使用foreach(BiConsumer bc)
    private static void test3(HashMap<String, String> map) {
        map.forEach((key, vlaue) -> System.out.println(key + "---" + vlaue));
    }
}

        案例: 

/*
现有字符串数组如下:
    String[] bookArr = {"《红楼梦》-曹雪芹","《西游记》-吴承恩","《三国演义》-罗贯中","《水浒传》-施耐庵"};
需求:
    请将字符串中的书名提取为Map集合的键,将作者提取为Map集合的值
    并使用三种不同方式,遍历Map集合打印键值对元素内容
*/
public class Demo3 {
    public static void main(String[] args) {
        String[] bookArr = {"《红楼梦》-曹雪芹","《西游记》-吴承恩","《三国演义》-罗贯中","《水浒传》-施耐庵"};
        HashMap<String, String> map = new HashMap<>();
        for (String str : bookArr) {
            String[] strs = str.split("-");
            map.put(strs[0], strs[1]);
        }

        Set<String> keys = map.keySet();
        for (String key : keys) {
            String value = map.get(key);
            System.out.println("作品:" + key + ", 作者:" + value);
        }

        System.out.println("--------------------------");
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println("作品:" + key + ", 作者:" + value);
        }

        System.out.println("--------------------------");
        map.forEach((key, value) -> System.out.println("作品:" + key + ", 作者:" + value));
    }
}

HashMap 

        HashMap集合的底层原理 

        HashMap跟HashSet的底层原理是一模一样的,都是基于哈希表实现的。

        实际上:原来学的Set系列集合的底层就是基于Map实现的,只是Set集合中的元素只要键数据,不要值数据而已。 

        哈希表

  • JDK8之前,哈希表 = 数组+链表
  • JDK8开始,哈希表 = 数组+链表+红黑树
  • 哈希表是一种增删改查数据,性能都较好的数据结构。

         1、HashMap的特点和底层原理?

                由键决定:无序、不重复、无索引。HashMap底层是哈希表结构的。

                基于哈希表。增删改查的性能都较好。

        2、HashMap如何实现键的唯一性的?

                依赖hashCode方法和equals方法保证的唯一。

                如果要存储的是自定义对象,需要重写hashCodeequals方法。

        LinkedHashMap集合的原理 

        底层数据结构依然是基于哈希表实现的,只是每个键值对元素又额外的多了一个双链表的机制记录元素顺序(保证有序) 

        实际上:原来学习的LinkedHashSet集合的底层原理就是LinkedHashMap

        TreeMap

  • 特点:不重复、无索引、可排序(按照键的大小默认升序排序,只能对键排序)
  • 原理:TreeMapTreeSet集合的底层原理是一样的,都是基于红黑树实现的排序。

         TreeMap集合同样也支持两种方式来指定排序规则

  • 让类实现Comparable接口,重写比较规则。
  • TreeMap集合有一个有参数构造器,支持创建Comparator比较器对象,以便用来指定比较规则。

        案例: 

/*
需求:创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String)。
        学生属性姓名和年龄,按照年龄进行排序并遍历。
*/
public class Demo6 {
    private String put;

    public static void main(String[] args) {
        //创建集合
        Map<Teacher, String> map = new TreeMap<>((o1, o2) -> {
            if (o1.getAge() == o2.getAge()) {
                return o1.getName().compareTo(o2.getName());
            } else {
                return o1.getAge() - o2.getAge();
            }
        });
        map.put(new Teacher("张三", 21), "河北");
        map.put(new Teacher("李四", 20), "山东");
        map.put(new Teacher("王五", 19), "山西");
        map.put(new Teacher("赵六", 21), "河南");

        map.forEach((k, v) -> {
            System.out.println(k + "-----" + v);
        });
    }
}

class Teacher {
    private String name;
    private int age;

    public Teacher() {
    }

    public Teacher(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

}

        补充知识:集合的嵌套

/*
集合嵌套
    要求在程序中记住如下省份和其对应的城市信息,记录成功后,要求可以查询出湖北省的城市信息。

数据
    江苏省 = "南京市","扬州市","苏州市","无锡市","常州市"
    湖北省 = "武汉市","孝感市","十堰市","宜昌市","鄂州市"
    河北省 = "石家庄市","唐山市","邢台市","保定市","张家口市"

分析:
    定义一个Map集合,键用表示省份名称,值表示城市名称,注意:城市会有多个。 Map<String,List<String>>
    根据“湖北省”这个键获取对应的值展示即可。
*/
public class Demo7 {
    public static void main(String[] args) {
        //创建一个Map集合。key是一个字符串,value是list集合
        HashMap<String, List<String>> map = new HashMap<>();
        //向map中存入,河北省和对应城市
        List<String> list1 = new ArrayList<>();
        Collections.addAll(list1, "石家庄市","唐山市","邢台市","保定市","张家口市");
        map.put("河北省", list1);
        //向map中存入,湖北省和对应城市
        List<String> list2 = new ArrayList<>();
        Collections.addAll(list2, "武汉市","孝感市","十堰市","宜昌市","鄂州市");
        map.put("湖北省", list2);
        //向map中存入,江苏省和对应城市
        List<String> list3 = new ArrayList<>();
        Collections.addAll(list3, "南京市","扬州市","苏州市","无锡市","常州市");
        map.put("江苏省", list3);

        List<String> list = map.get("河北省");
        System.out.println(list);
    }
}

Stream 

        什么是Stream?

  • 也叫Stream流,是Jdk8开始新增的一套API (java.util.stream.*)可以用于操作集合或者数组的数据。
  • 优势: Stream流大量的结合了Lambda的语法风格来编程,提供了一种更加强大,更加简单的方式操作集合或者数组中的数据,代码更简洁,可读性更好

/*
Stream流
    Jdk8开始新增的一套API,可以用于操作集合或者数组的数据

优势
    代码更简洁,可读性更好

使用流程
    集合/数组/…---->获取Stream流---->对流中的数据进行各种操作---->结果获取
                                   (排序、过滤、去重等等)     (收集、打印、统计)
*/
public class Demo1 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");

        //需求:把集合中所有以"张"开头,且是3个字的元素存储到一个新的集合。

        //实现1: 使用传统方式实现

        //实现2: 使用Stream流方式实现
        List<String> list1 = list.stream()
                .filter(new Predicate<String>() {
                    @Override
                    public boolean test(String s) {
                        return s.startsWith("张") && s.length() == 3;
                    }
                })
                .toList();
        System.out.println(list1);
    }
}

        Stream流的使用步骤

        1、Stream有什么作用? 结合了什么技术?

                简化集合、数组操作的API。

                结合了Lambda表达式。

        2、说说Stream流处理数据的步骤是什么?

                先得到集合或者数组的Stream流(获取)

                然后调用Stream流的方法对数据进行处理(操作)

                获取处理的结果(终结)

         Stream流的常用方法

         获取Stream流

        获取单列集合 Stream

Collection提供的如下方法

说明

default Stream<E> stream​()

获取当前集合对象的Stream

        获取 数组 Stream 

Arrays类提供的如下 方法

说明

public static <T> Stream<T> stream(T[] array)

获取当前数组的Stream

        获取 零散数据 Stream

Stream类提供的如下 方法

说明

public static<T> Stream<T> of(T... values)

获取当前接收数据的Stream

/*
使用流程
    集合/数组/…---->获取Stream流---->对流中的数据进行各种操作---->结果获取
                                   (排序、过滤、去重等等)     (收集、打印、统计)

如何获取Stream流
    Collection集合:
        单列集合都支持一个stream()方法,它可以直接获取集合的Stream流
    数组:
        Arrays.stream(数组)
    零散数据:
        Stream.of(T... values)
    Map
        双列集合并没有提供直接获取Stream流的方法,他需要间接获取
*/
public class Demo2 {
    public static void main(String[] args) {
        //"玄奘", "悟空", "悟能", "悟净"
        List<String> list = new ArrayList<>();
        list.add("玄奘");
        list.add("悟空");
        list.add("悟能");
        list.add("悟净");

        //Collection集合: 单列集合都支持一个stream()方法,它可以直接获取集合的Stream流
        Stream<String> stream = list.stream();

        //数组:Arrays.stream(数组)
        String[] strs = {"玄奘", "悟空", "悟能", "悟净"};
        Stream<String> stream1 = Arrays.stream(strs);
        //零散数据:Stream.of(T... values)
        Stream<String> stream2 = Stream.of("白龙马", "赵云", "电击小子");

        //Map:双列集合并没有提供直接获取Stream流的方法,他需要间接获取
        Map<String, String> map = new HashMap<>();
        map.put("001","玄奘");
        map.put("002","悟空");
        map.put("003","悟能");
        map.put("004","悟净");

        Stream<String> stream3 = map.keySet().stream();
    }
}

        Stream流常见的中间方法

        中间方法指的是对stream流进行操作的方法, 他们调用完成后会返回新的Stream流,可以继续使用(支持链式编程)

Stream提供的常用中间方法

说明

Stream<T> filter(Predicate<? super T> predicate)

用于对流中的数据进行过滤。

Stream<Tsorted()

对元素进行升序排序

Stream<Tsorted​(Comparator<? super T> comparator)

按照指定规则排序

Stream<T> limit​(long maxSize)

获取前几个元素

Stream<T> skip​(long n)

跳过前几个元素

Stream<T> distinct​()

去除流中重复的元素。

<R> Stream<R> map​(Function<? super T,​? extends R> mapper)

对元素进行加工,并返回对应的新流

static <T> Stream<T> concat​(Stream a, Stream b)

合并ab两个流为一个流

/*
中间方法
    对stream流进行操作的方法, 他们调用完成后会返回新的Stream流,可以继续使用(支持链式编程)。

常见的中间方法
    Stream<T> filter(Predicate<? super T> p) 按照规则过滤,保留满足条件的元素
    Stream<T> sorted() 升序排序
    Stream<T> sorted(Comparator<? super T> c) 按照规则排序
    Stream<T> limit(long maxSize) 截取
    Stream<T> skip(long n)  跳过
    Stream<R> map(Function<? super T, extends R> mapper) 对元素进行加工,并返回对应的新流
    Stream<T> distinct() 去重
    static <T> Stream<T> concat(Stream a,Stream b) 合并流
*/
public class Demo3 {
    public static void main(String[] args) {
        List<Integer> list = List.of(61, 57, 66, 77, 88, 44, 100, 89, 97, 47, 70);
        //需求1: 找出所有及格的分数,并打印
        System.out.println("=================");
        list.stream()
                .filter(e -> e >= 58 && e <= 90)
                .forEach(e -> System.out.println(e));
        //需求2: 找出所有及格的分数, 正序排列, 打印输出
        System.out.println("=================");
        list.stream()
                .filter(e -> e >= 60)
                .sorted((o1, o2) -> o1 - o2)
                .forEach(System.out::println);
        //需求3: 找出所有及格的分数, 倒序排列, 打印输出
        System.out.println("=================");
        list.stream()
                .filter(integer -> integer >= 60)
                .sorted(((o1, o2) -> o2 - o1))
                .forEach(System.out::println);
        //需求4: 找出所有及格的分数, 倒序排列, 取前3名, 打印输出
        System.out.println("=================");
        list.stream()
                .filter(integer -> integer >= 60)
                .sorted(((o1, o2) -> o2 - o1))
                .limit(3)
                .forEach(System.out::println);
        //需求5: 找出所有及格的分数, 倒序排列, 取前4-6名, 打印输出
        System.out.println("=================");
        list.stream()
                .filter(integer -> integer >= 60)
                .sorted(((o1, o2) -> o2 - o1))
                .skip(3)
                .limit(3)
                .forEach(System.out::println);
        //需求6:  找出所有及格的分数, 倒序排列, 取前4-6名, 将每个人的分数加10分, 打印输出
        System.out.println("=================");
        list.stream()
                .filter(e -> e >= 60)
                .sorted(((o1, o2) -> o2 - o1))
                .skip(3)
                .limit(3)
                .map(new Function<Integer, Object>() {
                    @Override
                    public Object apply(Integer integer) {
                        return integer + 10;
                    }
                })
                .forEach(System.out::println);
        //需求7: 将下面两个集合中的元素进行合并去重



    }
}

         Stream流常见的终结方法

        收集方法就是把Stream流操作后的结果转回到集合或者数组中去返回

Stream提供的常用终结方法

说明

Object[] toArray()

把流处理后的结果收集到一个数组中去

R collect​(Collector collector)

把流处理后的结果收集到一个指定的集合中去

Collectors工具类提供了具体的收集方式

说明

public static <T> Collector toList​()

把元素收集到List集合中

public static <T> Collector toSet​()

把元素收集到Set集合中

public static  Collector toMap​(Function keyMapper , Function valueMapper)

把元素收集到Map集合中

/*
终结方法
    调用完成后,不会返回新Stream了,没法继续使用流了。
    它的作用是对流中的数据进行筛选(遍历、最大、最小、统计个数)
    
常用方法
    void forEach(Consumer consumer)  遍历流中的数据
    long count() 统计流中元素的个数
    Optional max(Comparator<? super T> comparator) 获取流中的最大值
    Optional min(Comparator<?super T> comparator) 获取流中的最小值
*/
public class Demo4 {
    public static void main(String[] args) {
        List<Student> list = List.of(
                new Student("玄奘", 60, 165.5),
                new Student("悟空", 50, 175.5),
                new Student("悟能", 55, 145.5),
                new Student("悟净", 40, 185.5)
        );

        //1. 打印出集合中所有元素
        list.stream()
                .forEach(e -> System.out.println(e));
        //2. 统计出身高不足170的人数
        long count = list.stream()
                .filter(e -> e.getHeight() < 170.0)
                .count();
        System.out.println(count);
        //3. 请找出年龄最大的对象, 并输出(了解)
        Optional<Student> max = list.stream()
                .max(new Comparator<Student>() {
                    @Override
                    public int compare(Student o1, Student o2) {
                        return o1.getAge() - o2.getAge();
                    }
                });
        System.out.println(max);//Optional[Student{name='玄奘', age=60, height=165.5}]
        Student student = max.get();
        System.out.println(student);//
        //4. 请找出身高最高的对象, 并输出(了解)
        list.stream()
                .max((o1, o2) -> o1.getHeight() > o2.getHeight() ? 1 : -1);
    }
}

class Student {
    private String name;
    private int age;
    private double height;

    public Student() {
    }

    public Student(String name, int age, double height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }
}

递归 

        什么是方法递归?

  • 递归是一种算法,在程序设计语言中广泛应用。
  • 从形式上说:方法调用自身的形式称为方法递归( recursion)。

        递归的形式

  • 直接递归:方法自己调用自己。
  • 间接递归:方法调用其他方法,其他方法又回调方法自己。

        使用方法递归时需要注意的问题:

  • 递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误。

         案例:

/*
案例
    计算n的阶乘

阶乘
    5! = 5 * 4 * 3 * 2 * 1
    4! = 4 * 3 * 2 * 1
    3! = 3 * 2 * 1
    2! = 2 * 1
    1! = 1

    n! = n * (n-1) * (n-2) *.....* 1

公式
    f(n) = f(n-1) * n
*/
public class Demo2 {
    public static void main(String[] args) {
        System.out.println(f(5));
    }
    public static int f(int num) {
        if (num <= 1) {
            return 1;
        }else {
            return num * f(num - 1);
        }
    }
}

/*
案例
    计算1-n的和

阶乘
    5 = 5 + 4 + 3 + 2 + 1
    4 = 4 + 3 + 2 + 1
    3 = 3 + 2 + 1
    2 = 2 + 1
    1 = 1

    n = n + (n-1) + (n-2) +.....+ 1

公式
    f(n) = f(n-1) + n
*/
public class Demo3 {
    public static void main(String[] args) {
        System.out.println(f(5));
    }
    public static int f(int num) {
        if (num <= 1) {
            return 1;
        }
        return num + f(num - 1);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值