• Javaの集合学习


    • 集合
      集合和数组很类似,都是容器可以存放多个数据。但是数组有一个致命的弱点,数组长度固定不能动态增加。所以jdk就有创建了另外一种可以动态的随意增加长度的容器,叫做集合
    • 集合的分类(不同的集合之间,存放在它们里面的数据的类型特点不一致)
      Collection集合:又分为了List集合和Set集合
      Map集合:

    • List集合
        容器:存储数据
               基本功能:增删改查
               增加:
                  boolean add(E e) 将指定的元素追加到此列表的末尾(可选操作)。 
                  id add(int index, E element) 将指定的元素插入此列表中的指定位置(可选操作)。
                  boolean addAll(Collection<? extends E> c) 按指定集合的迭代器(可选操作)返回的顺序将指定集合中的所有元素附加到此列表的末尾。   
                  boolean addAll(int index, Collection<? extends E> c) 将指定集合中的所有元素插入到此列表中的指定位置(可选操作)。
               删除:
                  void clear() 从此列表中删除所有元素(可选操作)。 
                  void remove(int index) 删除该列表中指定位置的元素(可选操作)。  
                  boolean remove(Object o) 从列表中删除指定元素的第一个出现(如果存在)(可选操作) 
                  boolean removeAll(Collection<?> c) 从此列表中删除包含在指定集合中的所有元素(可选操作)。   
               修改:
                 E set(int index, E element) 用指定的元素(可选操作)替换此列表中指定位置的元素。    
               查询:  
                 E get(int index) 返回此列表中指定位置的元素。 
                 Iterator<E> iterator() 以正确的顺序返回该列表中的元素的迭代器。 
                 Iterator迭代器对象
                        hasNext():可以通过它判断 集合里面是否还有下一个元素
                        next():获取下一个元素
                 ListIterator<E> listIterator() 返回列表中的列表迭代器(按适当的顺序)。 
                        正向迭代:
                             ListIterator lit =list.listIterator();
                               while(lit.hasNext()){
                                  System.out.println(lit.next());
                              }
                        反向迭代:
                              while(lit.hasPrevious()){
                                  System.out.println(lit.previous());
                               }
                        注意:使用反向迭代,先要正向迭代一次。
                 ListIterator<E> listIterator(int index) 从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。 
               判断:
                  boolean contains(Object o) 如果此列表包含指定的元素,则返回 true
      常用子类:
                  ArrayList:底层是数组结构,默认长度是10,当我们存储的数据超过了10个之后,它会自动的增加原来的一半也是自动增加5个长度
                  LinkedList:底层是链表结构,无下标排序。
                    例子: 模拟堆栈和队列的特点
                         堆栈:先进后出 (如同水杯)
                         队列:先进先出 (如同水管)
                  Vector :底层是数组结构,默认长度是10,超过默认长度自增10个。它和list相比是线程安全。这个是jdk1.2就有的原始元素,以及被ArrayList淘汰

      代码实例

      package com.ly.listapi;
      
      import java.util.ArrayList;
      import java.util.Iterator;
      import java.util.List;
      import java.util.ListIterator;
      
      /**
       * 使用ArrayList测试List的api
       */
      public class ListApi {
          public static void main(String[] args) {
              //创建一个集合
              List list =new ArrayList();
              List list2 =new ArrayList();
              String str="hi update";
              list2.add(1);
              list2.add(2);
              //添加元素
              list.add("张三");
              list.add(true);
              list.add(10);
              list.add(0.001f);
              list.add("1234444");
              //制定的下标添加
              list.add(2,"hi");
              //在制定的下标插入一个集合
              list.addAll(3,list2);
      //        System.out.println(list2.size());
              //删除集合中所有的元素
             /* list2.clear();*/
      //        System.out.println(list2.size());
              System.out.println("----------------------");
              list.remove(0);
              list.remove(true);
              list.removeAll(list2);
              //修改元素
              list.set(0,"hi update");
              //包含
      //        System.out.println(list.contains(str));
              /**
               * 遍历集合 (4种)
               */
              /*for(int i=0;i<list.size();i++){
                  System.out.println(list.get(i));
              }*/
             /* for(Object obj:list){
                  System.out.println(obj);
              }*/
              /***
               * 集合特有的迭代方式 迭代器
               */
             /* Iterator it =list.iterator();
              while(it.hasNext()){
                  System.out.println(it.next());
              }*/
              /***
               * 正向迭代
               */
                 ListIterator lit =list.listIterator();
                 while(lit.hasNext()){
                  System.out.println(lit.next());
              }/**/
              /***
               * 反向迭代
               */
              /* ListIterator lit =list.listIterator();*/
               while(lit.hasPrevious()){
                  System.out.println(lit.previous());
               }
      //        System.out.println(list.size());
          }
      }
      package com.ly.linkedListDemo;
      
      import java.util.LinkedList;
      import java.util.List;
      
      /***
       * 使用linkedList 完成堆栈和队列的效果
       *  removeFirst()
          从此列表中删除并返回第一个元素。
         removeLast()
          从此列表中删除并返回最后一个元素。
       */
      public class LinkedListDemo {
          public static void main(String[] args) {
              LinkedList list =new LinkedList();
              list.add(111);
              list.add("222");
              list.add(true);
            /*  while(!list.isEmpty()){
                  System.out.println(list.removeLast());
              }*/
              while(!list.isEmpty()){
                  System.out.println(list.removeFirst());
              }
      
          }
      }
    • ArrayList去重(其类一致的时候会将值进行比较【个人理解,里面存储的数据类型不一样,例如Person类,遇上相同的数据类型会调用本类(例如同样是Person就调用Person)中的equals方法,但像Person这样不具备比较性的则要继承Comparable类来实现重写equal方法】
        依据equal方法(正常情况是使用hash值),则此时我们需要重写equal方法
      public class ArrayListDemo {
          public static void main(String[] args) {
              ArrayList list =new ArrayList();
              Person p=new Person();
              p.setAge(19);
              p.setUsername("aaaa");
              p.setPassword("aaaa");
              list.add(p);
              Person p1=new Person();
              p1.setAge(19);
              p1.setUsername("aaa1");
              p1.setPassword("aaaa");
              list.add(p1);
              ArrayList newList= replaceList(list);
              for(int i=0;i<newList.size();i++){
                  Person pi= (Person)newList.get(i);
                  System.out.println(pi.getUsername());
              }
          }
       private static ArrayList replaceList(ArrayList list) {
              ArrayList newlist =new ArrayList();
              Iterator it =list.iterator();
              while(it.hasNext()){
                  Object obj =it.next();
                  if(!newlist.contains(obj)){
                      newlist.add(obj);
                  }
              }
              return newlist;
          }
      
      }
      package com.ly.po;
      
      /***
       * 用户对象
       */
      public class Person implements Comparable{
           private String username;
           private String password;
           private int age;
      
          public String getUsername() {
              return username;
          }
      
          public void setUsername(String username) {
              this.username = username;
          }
      
          public String getPassword() {
              return password;
          }
      
          public void setPassword(String password) {
              this.password = password;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          @Override
          public int hashCode() {
              return 0;
          }
      
          public Person() {
          }
      
          public Person(String username, String password, int age) {
              this.username = username;
              this.password = password;
              this.age = age;
          }
      
          @Override
          public boolean equals(Object obj) {
              if(obj instanceof Person){
                  return this.username.equals(((Person) obj).getUsername()) && this.age==((Person) obj).getAge() && this.password.equals(((Person) obj).getPassword());
              }else{
                  return false;
              }
          }
           //p.compareTo(p1){}
          @Override
          public int compareTo(Object o) {
              if(o instanceof  Person){
                  Person p =(Person) o;
                  return (this.getUsername().hashCode()-p.getUsername().hashCode()) -(this.age-p.age) -(this.getPassword().hashCode()-p.getPassword().hashCode());
              }
              return -1;
          }
      }

      这个的思路是:新建一个集合,迭代list,建立一个Object对象,使其通过if(!newlist.contains(obj))方法来实现判断【这里contains()方法会引用equals方法(所以需要重写equals方法),此时会将集合里的数据调用equal方法去比较obj】如果不包含则add()加入,包含则不添加

    • List有序,元素可重复,集合有索引  ||  Set无序,元素不可重复,集合无索引


    • Set的共性方法与List差不多
      1.HashSet底层是哈希表(由哈希值(有16位进制组成的数)组成的表),在Java中每个元素都有一个HashCode方法,方法返回所在的物理内存地址(一般情况下每个数的hash值不同)
      (输出对象(例如Person p)输出p(如果没有toString方法,则输出物理内存地))
    • HashSet无顺序,不允许重复
      HashSet存自定义对象去重思路:比较重复是根据hashcode值来比较,如果一样就使用equal方法再进行比较,但一般情况下hashcode的值是不相同的,所以要在自定义对象中重写hashcode方法使hashcode的值相等【public int hashcode( return 50;)】
      package com.ly.com.ly.setdemo;
      
      import com.ly.po.Person;
      
      import java.util.HashSet;
      import java.util.Iterator;
      
      /***
       * 测试hashset
       */
      public class HashSetDemo {
          public static void main(String[] args) {
              HashSet set =new HashSet();
              set.add("java 01");
              set.add("java 02");
              set.add("java 03");
              set.add("java 04");
              set.add("java 01");
              set.add("java 03");
      
              Iterator it =set.iterator();
              while(it.hasNext()){
                  System.out.println(it.next());
              }
              Person p=new Person();
              p.setUsername("zhangsan");
              p.setPassword("123456");
              p.setAge(19);
              Person p2 =new Person();
              p2.setUsername("zhangsan");
              p2.setPassword("123456");
              p2.setAge(19);
              HashSet pset =new HashSet();
              pset.add(p);
              pset.add(p2);
              Iterator it1 =pset.iterator();
              while(it1.hasNext()){
                  System.out.println(it1.next());
              }
          }
      }
    • TreeSet 有序无下标,以二叉树来比较,底层是二分叉树,有自己的排序规则,存放元素必须具备比较性(八大元素和String都实现了Comparable)
      要是自定义对象具备比较性,实现Comparable接口,实现comparableTo方法来进行比较【public int comparableTo(Object o){。。。}】
      package com.ly.com.ly.treesetdemo;
      
      import com.ly.com.ly.comable.MyComparator;
      import com.ly.po.Person;
      
      import java.util.Iterator;
      import java.util.TreeSet;
      
      public class TreeSetDemo {
          public static void main(String[] args) {
             /* TreeSet tset =new TreeSet();*/
      //        tset.add(true);
      //        tset.add(false);
      //        tset.add("java 03");
      //        tset.add("java 04");
      //        tset.add("java 01");
      //        Iterator it =tset.iterator();
      //        while(it.hasNext()){
      //            System.out.println(it.next());
      //       }
             TreeSet tset =new TreeSet(new MyComparator());
             Person p =new Person("211","1111",22);
             Person p1 =new Person("222","2222",30);
             Person p2 =new Person("123","2222",30);
             tset.add(p);
             tset.add(p1);
             //p和p1已经比较完了  p p1  p1 p
             tset.add(p2);
              Iterator it =tset.iterator();
              while(it.hasNext()){
                  Person obj =(Person)it.next();
                  System.out.println(obj.getUsername());
              }
      
          }
      }
      package com.ly.com.ly.comable;
      
      import com.ly.po.Person;
      
      import java.util.Comparator;
      
      public class MyComparator implements Comparator{
      
          @Override
          public int compare(Object o1, Object o2) {
              if(o1 instanceof Person && o2 instanceof  Person){
                 return (((Person) o1).getUsername().hashCode()+((Person) o1).getPassword().hashCode()+((Person) o1).getAge())
                            -
                         (((Person) o2).getUsername().hashCode()+((Person) o2).getPassword().hashCode()+((Person) o2).getAge());
              }
              return 0;
          }

          /**
           * 实现Comparable 接口
           * 然后实现compareTo方法
           * @param o
           * @return
           */
          public int compareTo(Object o) {
              if (o instanceof User) {
                  User user = (User) o;
                  //比较两个对象的age 返回的是它们的减法值,如果this.age>user.age返回正数,反之返回负数,相等返回0
                  return this.age-user.age;
      //            System.out.println("this:"+(this.name.hashCode()+this.age));
      //            System.out.println("user:"+(user.name.hashCode()+user.age));
      //            System.out.println("compare:"+((this.name.hashCode()+this.age)-(user.name.hashCode()+user.age)));
      //            return (this.name.hashCode()+this.age)-(user.name.hashCode()+user.age);
              }else{
                  throw new RuntimeException("不是用户类");
              }
          } },

      思路:TreeSet在add()对象时会自动将对象排序,但需要有可比较性,如自定义类就需要实现comparable类,实现comparableTo方法才可以进行比较

    • TreeSet可以自传比较器(其本身自带二叉树比较)
      除了上面那种实现接口比较以外,还有一种比较方式:
      
      /**
       * 新建一个比较器对象
       * @author Administrator
       *
       */
      public class MyCompare implements Comparator{
      
          /**
           * 编写具体的比较规则
           */
          public int compare(Object o1, Object o2) {
              if(o1 instanceof User && o2 instanceof User){
                  User user1 =(User)o1;
                  User user2 =(User)o2;
                  return user1.getAge()-user2.getAge();
              }else{
                  throw new RuntimeException("要比较的类型不一致无法比较");
              }
      
          }
      
      }
      
        public static void main(String[] args) {
                TreeSet set1 =new TreeSet(new MyCompare());
                   set1.add(new User("java01",11));
                   set1.add(new User("java02",12));
                   set1.add(new User("java01",11));
                   set1.add(new User("java03",13));
                   Iterator it1 =set1.iterator();
                   while(it1.hasNext()){
                         System.out.println(it1.next());
                  }
       

      当自定义(就是自己重写的equals方法)和比较器(自己写的)都存在时,以比较器为主

    • HashSet和TreeSet的区别
      HashSet        底层是哈希表,没有顺序,不允许重复
      TreeSet       底层是二叉树结构,有顺序 ,不允许重复
      但它们都是存储数据的容器
    • 泛型  由于集合数据类型不同,迭代大多需要强行转型(由大转小可能导致数据丢失),所以泛型应此而生了
      泛型:因为集合可以存储任意对象的元素,所以在开发过程中无法保证集合内元素的一致性,在早期的遍历过程中,
      需要我们不断的去把Object 转换成我们所需要的对象的类型,来过滤掉其他数据类型,遍历出来。时间长了程序员就觉得这样很麻烦,
      于是就有了泛型。泛型提供了更好的解决方案:类型参数。例如,ArrayList类用一个类型参数来指出元素的类型。 泛型是Java
      1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。 这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java泛型被引入的好处是安全简单。 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,
      而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。 泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

      作用:
      1.申明准确类型(申明定义准确类型,集合只能插入准确的类型)

      package com.ly.com.ly.genericity;
      
      import com.ly.po.Person;
      
      import java.util.ArrayList;
      
      /***
       * 通过ArrayList 来说明泛型的作用
       * 1.申明准确的类型
       *     声明的时候就顶了准确的类型,以后集合里面只能插入定义的类型
       */
      public class ArrayListDemo {
          public static void main(String[] args) {
              ArrayList<Person> plist=new ArrayList<>();
              plist.add(new Person("aaa","aaaa",18));
              for(Person p:plist){
                  System.out.println(p.getUsername()+"	"+p.getPassword()+"	"+p.getAge());
              }
          }
      }

      2.定义了抽象类型(一般用来编写扩展性强的类或者是工具类)

      package com.ly.com.ly.dao;
      
      import com.ly.po.stu;
      //T 或者E 你就可以看成是Object
      public class BaseDao<T>{
             private T t;
             public void add(T t){
                 System.out.println(t+"添加");
             }
             public void update(T t){
                 System.out.println(t+"修改");
             }
             public void find(T t){
                 System.out.println(t+"查询");
             }
             public void delete(T t){
                 System.out.println(t+"删除");
             }
      }

      然后接下来顺便将例子放出

      package com.ly.com.ly.test;
      
      import com.ly.com.ly.dao.StuDao;
      import com.ly.com.ly.dao.teacherDao;
      import com.ly.po.stu;
      import com.ly.po.teacher;
      
      public class demo {
          public static void main(String[] args) {
              teacher t =new teacher("t1","男",1000);
              teacherDao tdao =new teacherDao();
              tdao.add(t);
              tdao.update(t);
             /* tdao.addtea(t);
              tdao.updatetea(t);
              tdao.findtea(t);
              tdao.deletetea(t);*/
              stu s =new stu("aaa","男","软件1班");
              StuDao dao =new StuDao();
              dao.add(s);
              /*dao.addStu(s);
              dao.updatestu(s);
              dao.findstu(s);
              dao.deletestu(s);*/
          }
      }
      package com.ly.com.ly.dao;
      
      import com.ly.po.stu;
      import org.junit.Test;
      
      /***
       * 模拟完成stu的增删改查方法
       * */
      public class StuDao extends BaseDao{
          /*public void addStu(stu stu){
              System.out.println(stu+"添加");
          }
          public void updatestu(stu stu){
              System.out.println(stu+"修改");
          }
          public void deletestu(stu stu){
              System.out.println(stu+"删除");
          }
          public void findstu(stu stu){
              System.out.println(stu+"查询");
          }*/
      }
      package com.ly.com.ly.dao;
      
      
      import com.ly.po.stu;
      import com.ly.po.teacher;
      
      public class teacherDao extends  BaseDao{
          /*public void addtea(teacher tea){
              System.out.println(tea+"添加");
          }
          public void updatetea(teacher tea){
              System.out.println(tea+"修改");
          }
          public void deletetea(teacher tea){
              System.out.println(tea+"删除");
          }
          public void findtea(teacher tea){
              System.out.println(tea+"查询");
          }*/
      }
    • Map集合
      java中的map集合使用键(key)值(value)来保存数据,其中值(value)可以重复,但键(key)必须是唯一,也可以为空,但最多只能有一个key为空,
      它的主要实现类有HashMap、LinkedHashMap、TreeMap。
      共性方法:
          1.添加:
             put();
             putAll();
          2.删除
             clear();清空数据
             remove();通过Key删除单个值,还可以放集合删除
          3.判断
            containsKey(Object key);
            containsValue(Object value);
            isEmpty();
          4.获取
             get();
             size();
             values();
             entrySet();
             keySet(); 
      
      map的遍历:
            Map<String, String> map=new HashMap<String,String>();
                map.put("01", "java 01");
                map.put("02", "java 02");
                map.put("03", "java 03");
                map.put("04", "java 04");
                map.put("05", "java 05");
            
            /**
                 * 遍历方式1
                 */
                //获取到map中key值的集合
                Set<String> keys= map.keySet();
                //遍历其中的key值的集合
                Iterator<String> it=keys.iterator();
                //根据key获取到value
                while(it.hasNext()){
                    String key =it.next();
                    String value =map.get(key);
                    System.out.println("key:"+key+" value:"+value);
                }
              /**
                 * 遍历方式2
                 */
                //获取到map的关系映射放到set集合中
                Set<Map.Entry<String, String>> sets =map.entrySet();
                //迭代集合
                Iterator<Map.Entry<String, String>> it2=sets.iterator();
                while(it2.hasNext()){
                    //获取到集合中的每个映射关系
                    Map.Entry<String, String> map2 =it2.next();
                    //获取key和value
                    System.out.println("key:"+map2.getKey()+" value:"+map2.getValue());
                }
      package com.ly.mapdemo;
      
      import java.util.HashMap;
      import java.util.Iterator;
      import java.util.Map;
      import java.util.Set;
      
      /***
       * 学习map的数据类型
       * mapapi:
       *     V put(K key, V value)
               将指定的值与该映射中的指定键相关联(可选操作)
       */
      public class HashMapDemo {
          public static void main(String[] args) {
              HashMap map =new HashMap();
              HashMap map1 =new HashMap();
              map1.put(null,"ssss");
              map1.put("lll",1111);
              /***
               * map添加 key,value
               * k,v
               */
              map.put("aaa",1111);
              map.put("cccc",222);
              map.put("aaa",2222);
              map.putAll(map1);
              System.out.println(map.containsKey("sskl;sks;lsk"));
              System.out.println(map.containsValue("1111"));
              System.out.println(map.get(null));
      //        map1.clear();
              map1.remove(null);
              System.out.println(map1.size());
              /***
               * map的数据结构比较特殊,它是存一组数据,那如果来区分存进去的每组数据和每组数据列,它是通过列名来区分
               * 所以说key  的值不允许出现重复的,或者会覆盖原先的数据。
               */
              System.out.println(map.size());
              /***
               * map遍历方式1
               */
             /* Set keySet=map.keySet();
              Iterator it =keySet.iterator();
              while(it.hasNext()){
                  System.out.println(map.get(it.next()));
              }*/
              /***
               * 第二种遍历方式
               */
              Set<Map.Entry<String,Object>> set = map.entrySet();
              Iterator<Map.Entry<String,Object>> it =set.iterator();
              while(it.hasNext()){
                  Map.Entry<String,Object> obj=it.next();
                  System.out.println(obj.getKey()+":"+obj.getValue());
              }
          }
      }

      思路:上面entryset()看成是一个Set对象,Map集合名.Entry<数据类型,数据类型>是将集合看成由一个个Key和Value组成的对象



    • Hashtable:底层是哈希表的数据结构,不可以存入null键和null值,是线程同步的。jdk1.0效率低
      HashMap:底层也是哈希表数据结构,允许存入null键null值,线程不同步。(这 HashMap类大致相当于 Hashtable,除了它是不同步的,允许空值。)jdk2.0效率高
      TreeMap:底层是二叉树结构,线程不同步,可以给map集合中的key 进行排序。
      总结:通过这三个具体类的描述,我们发现它和set集合是不是很像,其实set集合底层调用的都是map集合的方法。

    • 例子
      我们用user对象来作为key,判断如果年龄和姓名一样的user对象在map中只能有一个key存一个值。
      
      public class User implements Comparable{
          private String name;
          private int 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;
          }
          
          public User(String name, int age) {
              super();
              this.name = name;
              this.age = age;
          }
          public String toString() {
              return "User [name=" + name + ", age=" + age + "]";
          }
      
          /**
           * 重写hashCode方法
           *    
           */
      
          public int hashCode() {
              // TODO Auto-generated method stub
              return (name.hashCode()+age)*100;
          }
          /**
           * 重写 equals方法
           */
          public boolean equals(Object obj) {
              if(obj instanceof User){
                  User u =(User)obj;
                  return this.name.equals(u.name) && this.age==u.age;
              }else{
                  return false;
              }
          }
      
          /**
           * 重写比较性的方法
           */
          public int compareTo(Object o) {
              if(o instanceof User){
                  User u =(User)o;
                  int num=this.age-u.age;
                  if(num==0){
                      return this.name.compareTo(u.name);
                  }
                  return num;
              }else{
                 throw new RuntimeException("传错了");    
              }
          }
          
      }
      
      public class Test {
             public static void main(String[] args) {
      //          Map<User,String> map =new HashMap<User,String>();
                Map<User,String> map=new TreeMap<User, String>();
                map.put(new User("张三",18), "北京");
                map.put(new User("张三",18), "北京");
                map.put(new User("王武",18), "北京");
                map.put(new User("王武",18), "上海");
                map.put(new User("赵六",19), "武汉");
                /**
                 * 迭代
                 */
               Set<User> keys= map.keySet();
               Iterator<User> it= keys.iterator();
               while(it.hasNext()){
                   User user =it.next();
                   String value =map.get(user);
                   System.out.println("key:"+user+"  value:"+value);
               }
             }
      }
  • 相关阅读:
    MINA的session.close
    Maven构建灵活配置文件
    函数的凹凸性
    幂函数习题
    2017全国卷1文科第9题高考真题的解法
    指数函数习题
    三角形的四心的向量表示
    进退中体会数学运算和数学策略
    函数f(x+1)和f(x-1)的奇偶性
    函数的奇偶性周期性习题
  • 原文地址:https://www.cnblogs.com/YanZhuDL/p/11549672.html
Copyright © 2020-2023  润新知