最近总感觉时间不够用,要好好珍惜时间了。这篇就把剩下的部分补充完,关于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(&