最近总感觉时间不够用,要好好珍惜时间了。这篇就把剩下的部分补充完,关于java我想给大家整理的基本也就结束后了。其实记忆是个非常不靠谱的东西,我们必须落实到笔记上,多次加以复习才能得到巩固。

java中的高级数据结构

学习这个部分,对于有数据结构知识基础的同学应该掌握起来也比较简单,唯一难受的可能就是每个集合类有很多方法,需要记忆,如果要想足够的熟练只能多使用多记忆。我唯一能给大家建议的,在记忆这些方法的时候一定要注意:集合类是为了方便我们进行数据存储和读取的,那么掌握他的方法的时候可以遵循这样的一些逻辑:(1)我集合初始化方法有哪些(可不可以通过数组直接初始化);
(2)集合的增、删、改、查 对应的方法都是什么;
(3)集合的属性查询,比如大小、是否为空 是用什么方法;
(4)集合中的元素排序要怎么实现。
在学习的时候尽量往这四个方面进行归类,然后剩下的就是大家在刷题的时候在牛客网上多练习,尽量使用java相应的高级数据结构进行实现,一方面能够快速地解决题目,另一方面也使自己进一步熟悉java集合的使用。所以刷题其实也能够帮助我们进一步地熟悉我们所掌握的编程语言。

高级数据结构的分类

java的高级高级数据结构主要分为两种,

  • 一种是继承了Collection接口的集合类数据结构,
  • 一种是以前的旧有的实现,如Vetcor、Stack、Dicitionary、Hashtable、Properties、BitSet、Enumeration等。
    那么在java的集合类中又主要分了三大类结构:list、set和Map,其简单的特点可如下展示:

集合方法的简单分类

//数据结构初始化:
        //1.初始化为空数据结构
        //2.初始化为数据结构的大小以及增长因子
//增:单个增加或者批量增加元素;
        //1.在数据结构的尾部增加
        //2.在数据结构的指定位置增加
        //3.批量增加的时候是使用别的数据结构进行增加
//删:单个删除或者批量删除元素;
    //1.单个删除可以匹配具体的元素删除,或者是删除指定索引位置的元素
        //2.批量删除,删除某个索引范围内的元素
        //3.clear函数,清空整个数据结构
//改:单个修改或者批量修改元素;
//查:查找符合要求的单个或多个元素;
        //1.按照索引查找
        //2.按照元素的具体值查找
        //3.判断是否包含某一个元素

排序:这也是数据库提供的方法,在集合或高级数据结构中也适用;
集合的属性:如数据结构的长度、是否为空

用一张图汇总java中的集合类

再用一个表格进行一次汇总:

集合类使用的demo示例

其实记忆是很困难的,我们需要一些demo把一些关键的要点列举出来,从而可以在一个文章中多次复习。

旧的数据结构-Vector

旧的能够支持动态增长的数,https://www.runoob.com/java/java-vector-class.html
只想强调一下常用的几个方法即可:size(),get(),add(),remove(),clear(),set(i,o),contains(),indexof(),toArray()
新版本的vector实现了List接口,继承了AbstractList类。

@Test
    public void testVector(){
        Vector<String> vector = new Vector<String>();
        vector.add("lujuan");
        vector.add(0, "luchan");
        System.out.println("0: "+vector.get(0));//luchan
        vector.add("luhang");
        System.out.println("last: "+vector.lastElement());//luhang
        System.out.println("first: "+vector.firstElement());//luchan
        System.out.println("middle: "+vector.elementAt((vector.size()-1)/2));//lujuan
        vector.set(0,"luchanluchan");
        vector.setElementAt("lujuanlujuan",(vector.size()-1)/2);
        vector.remove(vector.size()-1);
        System.out.println("first: "+vector.firstElement());//luchan
        System.out.println("last: "+vector.elementAt((vector.size()-1)/2));//lujuan

    }

旧的数据结构-Stack

是Vector的子类,除了Vector中定义的方法外,还额外增加了一些属于栈属性的方法。这个结构体希望大家能尽量熟悉的掌握,在刷算法题目的时候必不可少的数据结构

@Test
public void StackVector(){
  Stack<Integer> stack = new Stack<Integer>();//只能用包装类
  boolean empty = stack.empty();//判断栈是否为空,为空返回true
  if(empty){
    for(int i=0; i< 5;i++)
      stack.push(i);//将元素放入栈中
  }
  while(!stack.empty()) {
    System.out.println(stack.peek());//获得顶部元素
    stack.pop();//移除顶部元素
  }
}

旧的数据结构-Hashtable

基本上有了HashMap之后,这个应该是使用频次非常少的数据结构。Java 2 重构的Hashtable实现了Map接口,因此,Hashtable现在集成到了集合框架中。它和HashMap类很相似,但是它支持同步。

像HashMap一样,Hashtable在哈希表中存储键/值对。当使用一个哈希表,要指定用作键的对象,以及要链接到该键的值。

public class HashTableUsing {
    @Test
    public void testHashtable(){
        Hashtable<String, Integer> hashtable = new Hashtable<String, Integer>();
        System.out.println("size of hashtable: "+hashtable.size());
        hashtable.put("lujuan", 1995);//存放key、value
        hashtable.put("luchan",1992);//存放key、value
        if(hashtable.containsKey("lujuan"))//判断是否又key值日
            System.out.println(hashtable.get("lujuan"));//获取相应的value值
        if(hashtable.contains(1995)){
            System.out.println(1995);
        }
        Enumeration<Integer> testValue = hashtable.elements();//对所有元素进行迭代
        while(testValue.hasMoreElements())System.out.println(testValue.nextElement());
        Enumeration<String> testKey = hashtable.keys();
        while(testKey.hasMoreElements()) System.out.println(testKey.nextElement());

        hashtable.remove("lujuan");
        hashtable.get("lujuan");
    }
}

旧的数据结构-Properties类

这个是做测试框架中的参数配置化的过程中我们经常使用的一个类,主要是从配置文件中进行相应配置参数的解析,所以大家还是又必要学习一些这个类型。
参考学习文档:https://www.cnblogs.com/***1/p/5462151.html
需要load函数从Reader中读取,然后store函数,存储在文件中。
getProperty setProperty 是两个关键函数

package keyPoint;

import org.testng.annotations.Test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Set;

public class HashTableUsing {

  @Test
  public void testPropertiesWrite() throws Exception{
    Properties properties = new Properties();
    properties.setProperty("lujuan", "1995");
    properties.setProperty("luchan","1992");
    FileOutputStream fileWriter = new FileOutputStream("jiapu.properties");//需要使用OutputStream 来存储
    properties.store(fileWriter,null);
    fileWriter.close();
  }
  @Test
  public void testPropertiesRead() throws Exception{
      Properties properties = new Properties();
      FileInputStream fileInputStream = new FileInputStream("jiapu.properties");//需要使用InputStream 来读取
      properties.load(fileInputStream);
      fileInputStream.close();
      Enumeration<?> keys = properties.keys();
      while(keys.hasMoreElements()){
        String key = (String)keys.nextElement();
        System.out.println(key+": "+properties.getProperty(key));
        properties.setProperty(key, "1978");
      }
      FileOutputStream fileOutputStream = new FileOutputStream("jiapu.properties");
      properties.store(fileOutputStream,null);
      fileOutputStream.close();
  }
}

旧的数据结构-Enumeration接口

至今为止没有怎么用过,可能主要是用在map类数据结构的迭代访问中。Enumeration是一个接口,作用类似于迭代器,接口中定义了两个方法hasMoreElement和nextElement,这个接口主要适用于旧的数据结构如Vector、Properties,以及其他的一个API上。

import java.util.Enumeration;
import java.util.Vector;
public class EnumerationUsing {
    @Test
     public void test(){
        Vector<String> vector = new Vector<String>(5);
        vector.add("1");
        vector.add("2");
        Enumeration<String> enumeration =null;
        enumeration = vector.elements();//elements中重写可接口中定义的Enumeration两个方法
        while(enumeration.hasMoreElements()){
            System.out.println(enumeration.nextElement());
        }
    }
}

旧的数据结构-BitSet

这也是一个不怎么用的数据结构。
BitSet的参考文章:https://www.cnblogs.com/xujian2014/p/5491286.html 写的挺好的。

import java.util.BitSet;
public class BitSetUsing {
    @Test
    public void test(){
        BitSet bitSet1 = new BitSet(16);//初始长度为8,每一位都为0
        BitSet bitSet2 = new BitSet();//无初始化的长度,内容可动态的增加
        for(int i = 0; i < 16;i++){
            if(i%2 == 0)bitSet1.set(i);
        }
        for(int i = 0; i < 16;i++){
            bitSet2.set(i);
        }
        System.out.println(bitSet1);//toString只返回为true的索引值,{0, 2, 4, 6, 8, 10, 12, 14}
        System.out.println(bitSet2);
        bitSet2.and(bitSet1); //and操作会改变bitSet2中的值
        System.out.println(bitSet2);

        bitSet2.or(bitSet1);//或操作
        System.out.println(bitSet2);

        bitSet2.xor(bitSet1);//yi或操作
        System.out.println(bitSet2);//bitSet2全部为false

        bitSet2.set(0,16);//没有办法获取这个set中有多少位,16位全部设置为true
        bitSet2.set(0,1,false);//设置0为false
        bitSet2.set(0,true);//设置0为true
        bitSet2.clear(0);//设置0为fasle
        bitSet2.clear();//设置全部为fasle
        bitSet2.clear(0,2);//设置0,1为fasle
        bitSet2.isEmpty();//如果全部为false,则返回true
        bitSet2.set(0,16);
        System.out.println(bitSet2);
        bitSet2.andNot(bitSet1);//如果全部为false,则返回true将bitSet1中设置为true的位置对应的值置为false
        System.out.println(bitSet2);
        System.out.println("length of bitSet1: "+bitSet1.length());//length是最高为true的索引的大小
        System.out.println("size of bitSet1: "+bitSet1.size());//实际占用的空间存储是大小,为64的整数倍
    }

}

集合类的公共父亲接口-Collection

我们知道父接口中有那些方法,能够帮助我们更好的进行记忆。
其实观察下来就是我们上面所列举的增删改查四种类型。

int size();
boolean isEmpty();

Object[] toArray();
<T> T[] toArray(T[] a);
Iterator<E> iterator();

boolean add(E e);
boolean addAll(Collection<? extends E> c);
boolean remove(Object o);
boolean removeAll(Collection<?> c);
void clear();
boolean retainAll(Collection<?> c);

boolean contains(Object o);
boolean containsAll(Collection<?> c);

boolean equals(Object o);
int hashCode()
//其他

集合类的迭代器iterator

java中的迭代器有两种:

Iterator<Student> iterator = list.iterator();//单向迭代器
ListIterator<Student> listIterator = list.listIterator();//双向迭代器

//单向迭代器的使用方法,主要是hasNext和next函数
iterator = list.iterator();
while(iterator.hasNext()){
  System.out.println(iterator.next());
}

两者的区别和详细比较:https://www.cnblogs.com/a842297171/p/5379130.html
只有list结构才能产生listIterator这样的迭代器。

集合类-list

Java中的List类型有ArrayList和LinkedList
List接口中定义的方法有

int size();
boolean isEmpty();
boolean contains(Object o);
boolean containsAll(Collection<?> c);
Iterator<E> iterator();
Object[] toArray();
boolean add(E e)
void add(int index, E element);
boolean addAll(Collection<? extends E> c);
boolean addAll(int index, Collection<? extends E> c);
boolean remove(Object o);
boolean removeAll(Collection<?> c);
int indexOf(Object o);
int lastIndexOf(Object o);
void clear();
default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }

ArrayList

public class ListUsing {

    class Student implements Comparable<Student>{
       public String name;
       public int grade;
       public Student(String name, int grade){
           this.name = name;
           this.grade = grade;
       }

        @Override
        public String toString() {
            return "name: "+ name +" grade: "+grade;
        }

        public int compareTo(Student o) {
            if(this.grade<o.grade)return -1;
            else{
                if(this.grade>o.grade)
                    return 1;
                else
                    return 0;
            }
        }
    }
    class ComparatorOfStudent implements Comparator<Student>{


        public int compare(Student o1, Student o2) {
            if(o1.grade > o2.grade)
                return -1;
            else{
                if(o1.grade < o2.grade)
                    return 1;
                else
                    return 0;
            }
        }
    }
    @Test
    public void testArrayList(){
        List<Student> list = new ArrayList<Student>();
        Student student1 = new Student("1",1);

        list.add(student1);
        int key = list.indexOf(student1);
        Student student2 = new Student("2", 2);
        list.set(key,student2);
        System.out.println(list.get(0).name);
        list.remove(student2);
        list.size();
        list.isEmpty();

        list.add(student1);
        list.add(student2);
        System.out.println("foreach遍历");
        for (Student s:list) {
            System.out.println(s.toString());
        }
        Iterator<Student> iterator = list.iterator();
        ListIterator<Student> listIterator = list.listIterator();
        System.out.println("迭代器遍历");
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }

        //从大到小排列
        System.out.println("从大到小排列");
        ComparatorOfStudent comparatorOfStudent = new ComparatorOfStudent();
        Collections.sort(list, comparatorOfStudent);//1.8中更推荐的是使用Collections中提供的算法。

        iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //从小到大排列
        System.out.println("从小到大排列");
        Collections.sort(list);//1.8中更推荐的是使用Collections中提供的算法。
        iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }

        System.out.println(list.contains(student2));//contains方法
        //清除list
        list.clear();
        System.out.println(list.size());

    }
}

LinkedList

//ArrayList的上述操作都能够使用LinkedList实现,只不过两者在不同场景下可能性能不同而已。
//ArrayList更适合用于随机访问的场所
//LinkedList更适合频繁增加和删除的场所。

集合类-set

三种Set集合的区别:https://blog.csdn.net/firearrow66/article/details/78858118
set接口定义的方法:

int size();
boolean isEmpty();

Object[] toArray();
<T> T[] toArray(T[] a);
Iterator<E> iterator();

boolean add(E e);
boolean addAll(Collection<? extends E> c);
boolean remove(Object o);
boolean removeAll(Collection<?> c);
void clear();
boolean retainAll(Collection<?> c);

boolean contains(Object o);
boolean containsAll(Collection<?> c);

boolean equals(Object o);
//其他的

HashSet

HashSet底层是用HashMap实现.我们来看一个简单的demo:



控制台输出

在hashset中我们需要注意,如果不重写类的hashCode和equal方法(两个方法均需要重写)那么,默认会把元素的引用本身来辨别元素是否相同,如上所示,虽然两个元素值一模一样,但是还是可以添加到set中。我们进行如下的重写,可以看到判断元素相同了之后,add就没有办法添加了。



控制台输出

HashSet添加的顺序与迭代显示的结果顺序并不一致,如果要保持一致,可以使用LinkedHashSet来实现,LinkedHashSet会按照元素投放的顺序进行遍历。下面是代码的demo:

import org.testng.annotations.Test;

import java.util.HashSet;
import java.util.Iterator;

public class SetUsing {
    class HashSetDemo{
        public String key;
        public int value;
        public HashSetDemo(String key, int value){
            this.key = key;
            this.value = value;
        }

        @Override
        public String toString() {
            return "key: "+this.key+" value: "+this.value;
        }

        @Override
        public int hashCode() {
            return this.key.hashCode();
        }

        @Override
        public boolean equals(Object obj) {
            if(this.key.equals(((HashSetDemo)obj).key))
                return true;
            else
                return false;
        }
    }
    @Test
    public void testHashSet(){
        HashSet<HashSetDemo> set1 = new HashSet<HashSetDemo>();
        HashSetDemo h1 = new HashSetDemo("1", 1);
        HashSetDemo h2 = new HashSetDemo("1", 2);
        set1.add(h1);//添加结果会返回false还是true
        System.out.println("重复元素的添加结果:"+set1.add(h2));
        Iterator<HashSetDemo> iterator = set1.iterator();
        while(iterator.hasNext())System.out.println(iterator.next());
        for(HashSetDemo h:set1)System.out.println(h);
        System.out.println("判断集合是否为空:"+set1.isEmpty());
        System.out.println("输出集合的大小:"+set1.size());
        set1.remove(h1);
        System.out.println("判断集合是否为空:"+set1.isEmpty());
        set1.add(h1);
        System.out.println("判断集合是否包含h2:"+set1.contains(h2));

    }
}

LinkedHashSet

元素先进先出,有顺序。

@Test
    public void testLinkHashSet(){
        HashSet<HashSetDemo> set1 = new HashSet<HashSetDemo>();
        HashSetDemo h1 = new HashSetDemo("10", 1);
        HashSetDemo h2 = new HashSetDemo(&