java 数据结构 、 List、 Set、collections

1.数据结构

    1.1. 常见的数据结构

          数据储存常用结构有:栈、队列、数组、链表、红黑树

      栈:

        :Stack  ,又称堆栈,它是运算受限的线性表,它的限制是仅仅允许在表的一端进行插入和删除操作,不允许在表的其他位置进行添加、查找、删除等操作。采取栈结构的集合,对元素的存取有以下特点。

            (1) 先进后出 :先存进去的元素,要等到后存进去的元素取出来才能取出。

             (2)栈的入口、出口都在栈的顶端位置。

                   

          压栈:就是存元素。就是把元素存储到栈的顶端位置,栈中的已有元素依次向栈底方向移动一个位置。

         弹栈:就是取元素。就是把栈顶端位置的元素取出来,栈中的已有元素依次向栈顶方向移动一个位置。

 

       队列:

           队列:queue,简称队列,它与堆栈一样,也是运算受限的线性表,它的限制是仅仅允许在表的一段进行插入,而在表的另一端进行删除。采用队列结构的集合,对元素的存取有以下特点。

           (1) 先进先出:先存进去的元素,先取出来。

           (2)队列的入口、出口各占一侧。

            

   

   数组:

       数组:Array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间中存放元素。就像一排房屋,有100个,每个房屋都有固定的编号,通过编号就可以找到具体的房屋。采用数组结构的集合,对元素的存取有以下特点。

         (1)查找元素块:通过索引,可以快速的访问指定位置的元素。

                                            

            (2)增删元素慢 :

                   指定索引位置增加元素:需要创建一个新数组,将指定新元素存储到指定索引位置,再把原数组元素根据索引,复制到新数组对应的索引位置。

                              

                    指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应的索引位置,原数组中指定的索引位置不复制到新数组中。

                              

     链表:

         链表:Linked List。是由一系列结点node(链表中每一个元素都成为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。链表结构有单向链表和双向链表。下面主要说单向链表结构。采用链表结构的集合,对于元素的存取有以下特点。

                                                                    

        (1)多个结点之间,通过地址进行连接

              

       (2)查找元素慢:要查找元素,需要通过连接的节点,依次向后查找指定的元素。

       (3)增删元素快:

                       增加元素:只需要修改连接下一个元素的地址即可。

                   

                  删除元素:只需要修改连接下一个元素的地址即可

                      

 

 

    红黑树:

            二叉数:binary tree 是每个结点不超过2的有序树(tree)。

           二叉树就是每个节点最多有两个子树的树结构。顶上的叫根节点,两边的被叫做“左子树”和“右子树”。

                                 

        红黑树:是二叉树的一种,红黑树本身就是一颗二叉查找树,将节点插入后,该树仍然是一颗二叉查找树,这就意味着树的键值仍然是有序的。

         红黑树的约束:

                           1.节点可以是红色的或者黑色的。

                           2.根节点是黑色的。

                           3.叶子节点(特指空节点)是黑色的

                           4.每个红色节点的子节点都是黑色的。

                           5.任何一个节点到其每一个叶子节点的所有路径上的黑节点数相同。

      红黑树的特点:

                         速度快,趋近于平衡数,查找叶子元素最少和最多次数不多于二倍。

       

   2.List集合

      2.1概述:

              list接口继承于collection接口,是单列集合的一个重要分支,习惯性的将实现了List接口的对象,称为List集合。List集合中允许出现重复的元素,所有的元素都是以线性方式进行存储的,在程序中可以通过索引去访问List集合中的元素。此外,List集合的另一个特点就是元素的存入顺序和取出顺序一致。 

      List接口的特点:

               (1)它是一个元素存取有序的集合。

                (2)它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素。

                 (3)集合中可以有重复元素,通过元素的equals方法,来比较是否为重复的元素。

     2.2  List接口中常用的方法

         List作为Collection接口的子接口,不但继承了Collection接口中的全部方法,并且还增加一些根据元素索引来操作集合的特有方法。

           public  void  add (int index,E element):将指定的元素添加到集合中的指定位置。

          public   E  get(int index) :返回集合中指定位置的元素。

           public   E remove( int index ):删除列表中指定位置的元素,返回的是被删除的元素。

          public   E set( int index ,E element):用指定的元素替换集合中指定位置的元素,返回的是被替换的元素

public class Text {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        list.add("乔巴1");
        list.add("乔巴2");
        list.add("乔巴3");
        list.add("乔巴4");
        System.out.println(list);//[乔巴1, 乔巴2, 乔巴3, 乔巴4]
        list.add(2,"乔巴");
        System.out.println(list);//[乔巴1, 乔巴2, 乔巴, 乔巴3, 乔巴4]
        String s = list.get(2);
        System.out.println("List集合中索引2处的元素为"+s);//List集合中索引2处的元素为乔巴
        String remove = list.remove(3);
        System.out.println("List集合中索引3处的元素为"+remove+"被删除");//List集合中索引3处的元素为乔巴3被删除
        System.out.println(list);//[乔巴1, 乔巴2, 乔巴, 乔巴4]
        String s1 = list.set(2, "路飞");
        System.out.println("List集合中索引2处的元素被换为"+s1);//List集合中索引2处的元素被换为乔巴
        System.out.println(list);//[乔巴1, 乔巴2, 路飞, 乔巴4]
    }
}

     3.List 的子类

      3.1 ArrayList集合

           java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快。

      3.2 LinkedList集合

        Java.util.LinkedList 集合数据存储的结构是链表结构。方便元素的添加、删除。LinkedList 是一个双向链表。双向链表的结构如下图:

            

       LinkedList 中提供了大量的操作首位的方法。

             public void addFirst(E e) :将指定元素插入此列表的开头。
             public void addLast(E e) :将指定元素添加到此列表的结尾。
             public E getFirst() :返回此列表的第一个元素。
             public E getLast() :返回此列表的最后一个元素。
             public E removeFirst() :移除并返回此列表的第一个元素。
             public E removeLast() :移除并返回此列表的最后一个元素。
             public E pop() :从此列表所表示的堆栈处弹出一个元素。
             public void push(E e) :将元素推入此列表所表示的堆栈。
             public boolean isEmpty() :如果列表不包含元素,则返回true。

   LinkedList 是 list 的子类,List中的方法LinkedList都可以使用,,LinkedList集合也可以作为堆栈,队列的结构使用。

public class Text {
    public static void main(String[] args) {
        LinkedList<String>  linkedList=new LinkedList<>();
        linkedList.addFirst("路飞");
        linkedList.addFirst("乔巴");
        linkedList.addFirst("山治");
        System.out.println(linkedList);//[山治, 乔巴, 路飞]
        linkedList.addLast("索隆");
        System.out.println(linkedList);//[山治, 乔巴, 路飞, 索隆]
        System.out.println("返回集合的第一个元素"+linkedList.getFirst());//返回集合的第一个元素山治
        System.out.println("返回集合的最后一个元素"+linkedList.getLast());//返回集合的最后一个元素索隆
        linkedList.removeFirst();//移除集合的第一个元素
        System.out.println(linkedList);//[乔巴, 路飞, 索隆]
        linkedList.removeLast();//移除元素的最后一个元素
        System.out.println(linkedList);//[乔巴, 路飞]
        while(!linkedList.isEmpty()){
            System.out.println("弹出栈顶的元素"+linkedList.pop());
            //弹出栈顶的元素乔巴     弹出栈顶的元素路飞
        }
        linkedList.push("娜美");
        System.out.println(linkedList);//[娜美]
    }
}

      4 set接口

       java.util.set接口是和java.util.list接口一样,是继承Collection接口,Set接口和Collection接口的方法基本一致,没有对Collection的方法就行扩充,但是它比Collection 接口更加严格了。与List集合不同的是,Set集合中的元素无序,并且保证集合中的元素不重复。

         Set集合有多个子类:java.util.HashSet 、java.util.LinkedHashSet这两个集合。

    4.1 HashSet集合

       java.util.HashSet是Set接口的一个实现类,它存储的元素是不可重复的,并且元素都是无序的(存和取的顺序不一样)。

     HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。它能保证元素的唯一性,依赖于:HashCode与equals方法。

public class Text {
    public static void main(String[] args) {
        HashSet<String> hs=new HashSet<>();
        hs.add("路飞");
        hs.add("索隆");
        hs.add("乔巴");
        hs.add("娜美");
        hs.add("路飞");
        System.out.println(hs);//[乔巴, 娜美, 索隆, 路飞]
    }
}

     从上述代码的输出可以看出,元素的输出和存入的顺序不同,并且不能存储重复元素。

   4.2 HashSet集合存储数据的结构(哈希表)

       哈希表:在JDK1.8之前,哈希表的底层是素组+链表实现的,使用了链表处理冲突,同一个哈希值的链表存储在一个链表里。但是当位于一个桶的元素较多时,即哈希值的相同的元素较多时,通过Key值一次查找的效率就比较低。在JDK1.8之后,哈希表存储采用数组+链表+红黑树来实现,当链表的长度超过阈值8时,将链表转换成红黑树,这样就增加了查找的效率。

        哈希表是有数组+链表+红黑树实现的。

   

          HashSet具体是怎么存储元素的,如下图:

   

       JDK 1.8 之后,大大优化了HashSet的性能,要保证HashSet集合中元素的唯一,就必须利用对象的HashCode和equals方法来确定。如果我们想要在HashSet集合中存储自定义的对象,就必须覆盖重写HashCode和equals方法。

 

 4.3 HashSet存储自定义类型元素

       当HashSet中存放自定义对象时,一样要重写对象中的HashCode和equals方法,用来确保集合中元素的唯一性。

import java.util.Objects;

public 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 +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        Student student = (Student) o;
        return getAge() == student.getAge() &&
                Objects.equals(getName(), student.getName());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getName(), getAge());
    }
}

public class Text {
    public static void main(String[] args) {
        HashSet<Student> hs=new HashSet<>();
        hs.add(new Student("路飞",18));
        hs.add(new Student("索隆",19));
        hs.add(new Student("山治",10));
        hs.add(new Student("路飞",18));
        System.out.println(hs);
        //[Student{name='路飞', age=18}, Student{name='索隆', age=19}, Student{name='山治', age=10}]
    }
}

      4.3 LinkedHashSet 

         目前我们知道HashSet集合可以保证元素的唯一性,但是元素的无序的,如果我们想要元素唯一,并且存取顺序一致,应该怎么做。在HashSet集合下,有一个java.util.LinkedHashSet,它是有链表和哈希表组合成的一个数组存储节结构。

public class Text {
    public static void main(String[] args) {
     LinkedHashSet<String>  lhs=new LinkedHashSet<>();
     lhs.add("路飞");
     lhs.add("索隆");
     lhs.add("山治");
     lhs.add("乔巴");
     lhs.add("路飞");
     System.out.println(lhs);//[路飞, 索隆, 山治, 乔巴]  
    }
}

     上述代码所示:LinkedHashSet集合,保证了元素的唯一性,并且确保了元素的存取顺序。 

5.可变参数

     在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且参数的类型一致,我们可以对其简化成一下格式:

       修饰符   返回值类型   方法名  (  参数类型... 形参名  )  {    }   

      上述格式等价于:修饰符  返回值类型  方法名(  参数类型[ ]  形参名 ) {  }

      第二种格式在调用时必须先创建数组,第一种格式就可以直接传递数据,就称为可变参数。

public class Text {
    public int sum1(int[] arr){
        int sum=0;
        for (int i : arr) {
            sum+=i;
        }
        return sum;
    }
    public int sum2(int... arr){
        int sum=0;
        for (int i : arr) {
            sum+=i;
        }
        return sum;
    }
    public static void main(String[] args) {
     Text t=new Text();
     int[] arr1={1,2,3,4,5,6,7,8,9,10};
     int i = t.sum1(arr1);
     System.out.println(i);
     int i1 = t.sum2(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
     System.out.println(i1);
    }
}

    6.Colltions

     6.1  Collections的常用功能

         java.utils.Collections是集合工具类,用来对集合进行操作,常用的方法如下:

         public static <T> boolean addAll(Collection<T> c, T... elements) :往集合中添加一些元素。

         public static void shuffle(List<?> list) 打乱顺序:打乱集合顺序。

         public static <T> void sort(List<T> list) :将集合中元素按照默认规则排序。

        public static <T> void sort(List<T> list,Comparator<? super T> ) :将集合中元素按照指定规则排序。
           

public class Text {
    public static void main(String[] args) {
        ArrayList<Integer> list=new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        System.out.println(list);//[1, 2, 3, 4]
        //往集合中添加元素
        Collections.addAll(list,5,6,7,8);
        System.out.println(list);//[1, 2, 3, 4, 5, 6, 7, 8]
        //打乱集合的顺序
        Collections.shuffle(list);
        System.out.println(list);//[7, 2, 3, 8, 6, 4, 5, 1]
        Collections.sort(list);//将集合按默认的顺序排序
        System.out.println(list);//[1, 2, 3, 4, 5, 6, 7, 8]
    }
}

   6.2 Comparator 比较器

          在Collections工具类中有默认排序方法:public static <T> void sort(List<T> list) :将集合中元素按照默认规则排序。

           但是如果集合中存储的事String类型的字符串呢?

public class Text {
    public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<>();
        //往集合中添加元素
        Collections.addAll(list,"cbc","ads","ddf","bfd");
        System.out.println(list);//[cbc, ads, ddf, bfd]
        Collections.sort(list);//将集合按默认的顺序排序
        System.out.println(list);//[ads, bfd, cbc, ddf]
    }
}

           我们使用的是默认的规则完成字符串的排序,那么默认规则是怎么定义出来的呢?

           说到排序了,简单的说就是两个对象之间比较大小,那么在JAVA中提供了两种比较实现的方式,一种是比较死板的
采用java.lang.Comparable 接口去实现,一种是灵活的当我需要做排序的时候在去选择的java.util.Comparator 接口完成。

         Collections工具类中的public static <T> void sort(List<T> list) 这个方法完成的排序,实际上要求了被排序的类型
需要实现Comparable接口完成比较的功能,在String类型上如下:

         public final class String implements java.io.Serializable, Comparable<String>, CharSequence { }

       String类实现了这个接口,并完成了比较规则的定义,但是这样就把这种规则写死了,那比如我想要字符串按照第
一个字符降序排列,那么这样就要修改String的源代码,这是不可能的了,那么这个时候我们可以使用:

       public static <T> void sort(List<T> list,Comparator<? super T> ) 方法灵活的完成,这个里面就涉及到了
Comparator这个接口,位于位于java.util包下,排序是comparator能实现的功能之一,该接口代表一个比较器,比
较器具有可比性!顾名思义就是做排序的,通俗地讲需要比较两个对象谁排在前谁排在后,那么比较的方法就是:

       public int compare(String o1, String o2) :比较其两个参数的顺序。

                      两个对象比较的结果有三种:大于,等于,小于。

                      如果要按照升序排序, 则o1 小于o2,返回(负数),相等返回0,01大于02返回(正数) 如果要按照
                      降序排序 则o1 小于o2,返回(正数),相等返回0,01大于02返回(负数)

public class Text {
    public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<>();
        //往集合中添加元素
        Collections.addAll(list,"cbc","ads","ddf","bfd");
        System.out.println(list);//[cbc, ads, ddf, bfd]
        Collections.sort(list, new Comparator<String>() {
                    @Override
                    public int compare(String o1, String o2) {
                        return o2.charAt(0)-o1.charAt(0);
                    }
                }
        );
        System.out.println(list);//[ddf, cbc, bfd, ads]  降序
    }
}

     6.3  Comparable 和Comparator 两个接口的区别

         Comparable:强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法
                                 被称为它的自然比较方法。只能在类中实现compareTo()一次,不能经常修改类的代码实现自己想要的排                                        序。实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序,对象可以                                     用作有序映射中的键或有序集合中的元素,无需指定比较器。

         Comparator: 强行对某个对象进行整体排序。可以将Comparator 传递给sort方法(如Collections.sort或
                                   Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator来控制某些数据结构(如有                                       序set或有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序。

public class Demo {
       // 创建四个学生对象 存储到集合中
         ArrayList<Student> list = new ArrayList<Student>();
         list.add(new Student("rose",18));
         list.add(new Student("jack",16));
         list.add(new Student("abc",16));
          list.add(new Student("ace",17));
          list.add(new Student("mark",16));
                   /*
          让学生 按照年龄排序 升序
                   */
                // Collections.sort(list);//要求 该list中元素类型 必须实现比较器Comparable接口
            for (Student student : list) {
                    System.out.println(student);
                   }
     }
}

         发现,当我们调用Collections.sort()方法的时候 程序报错了。        原因:如果想要集合中的元素完成排序,那么必须要实现比较器Comparable接口。于是我们就完成了Student类的一个实现,如下:

public class Student implements Comparable<Student>{
....
@Override
public int compareTo(Student o) {
return this.age‐o.age;//升序
}
}

   再次测试,代码就OK 了效果如下:

  

Student{name='jack', age=16}
Student{name='abc', age=16}
Student{name='mark', age=16}
Student{name='ace', age=17}
Student{name='rose', age=18}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值