集合

集合

1)缘由
    为了方便对对象进行操作
2)数组和集合的区别?
    都可以存储对象
    数组的长度不可变,集合的长度可变
    数组还可以存储基本数据类型,集合不可以
3)特点
专门用来存储对象:长度可变,可以存放不同类型的对象

1、Collection

是集合的根接口。集合里面元素可以是有序的,可以是无序的,可以是重复的,可以是唯一的
1)添加元素
add(Object obj):添加元素
addAll(Collection c):添加集合元素
2)删除功能
clear():清空
remove(Object obj):删除元素
removeAll(Collection c):删除集合元素
3)判断功能
isEmpty():是否为空
contains(Object obj):是否包含指定元素
containsAll(Collection c):是否包含指定的集合元素
4)获取功能
size():集合大小
Iterator<E> iterator():获取迭代器对象
5)、其他功能
Object[] toArray():集合转数组
retainAll(Collection c):两个集合交集操作

2、List接口

继承Collection接口,元素有序可重复
成员方法
add(int index,E ele):在指定的索引处添加指定元素
remove(int index):删除指定索引处的元素
get(int index):获取指定索引处的元素
set(int index,E ele):在指定索引处设置指定元素
ListIterator listIterator():获取列表迭代器

3、ListIterator

继承Iterator,允许正向或逆向遍历,且允许在迭代期间添加集合元素
boolean hasPrevious():是否有上一个元素
Object previous():获取上一个元素
add(E ele):添加元素

4、ArrayList

该类也是实现了List的接口,实现了可变大小的数组,随机访问和遍历元素时,提供更好的性能。该类也是非同步的,在多线程的情况下不要使用。ArrayList 增长当前长度的50%,插入删除效率低。

底层结构是数组,查询元素快,增加删除慢
线程不安全,不同步,效率高

5、Vector

底层结构是数组,查询元素快,增加删除慢
线程安全,同步,效率低
特有功能
addElement(E e):添加元素
E elementAt(int index):获取指定索引处的元素
Enumeration elements():获取集合所有元素构成的一个枚举对象

Enumeration类里面方法
hasMoreElements():是否有更多元素
nextElement():获取下个元素

6、栈Stack

栈是Vector的一个子类,它实现了一个标准的后进先出的栈。
成员方法
E peek():获取栈顶元素
E pop():弹栈(获取栈顶元素并移除)
E push(E e):压栈(将元素添加到栈中)

7、常见的数据结构

数据结构:数据存储方法
1)栈:先进后出
2)队列:先进先出
3)数组:查询快,增删慢
4)链表:查询慢,增删快
5)树
6)哈希表

8、LinkedList(双向链表)

该类实现了List接口,允许有null(空)元素。主要用于创建链表数据结构,该类没有同步方法,如果多个线程同时访问一个List,则必须自己实现访问同步,解决方法就是在创建List时候构造一个同步的List。例如:

List list = Collections.synchronizedList(new LinkedList(...));

底层是链表,查询慢,增删快
线程不安全,效率高
特有功能
addFirst(E e):添加首元素
addLast(E e):添加末元素
getFirst():获取首元素
getLast():获取末元素
E removeFirst():移除首元素
E removeLast():移除末元素

集合的遍历方式:

public static void main(String[] args) {

               List list = new ArrayList();
               //添加指定元素
               list.add("hello");
               list.add("java");
               list.add("world");

               //在Java后面添加javase
               list.add(2,"javase");
               System.out.println(list);

               //删除javase
               list.remove(2);
               //获取第一个元素
               System.out.println(list.get(0));
               //设置最后一个元素haha
               list.set(list.size()-1,"haha");
               System.out.println(list);

               //遍历方式1
               /*Iterator i = list.iterator();
               while(i.hasNext()){
                       String s = (String) i.next();
                       System.out.println(s);
               }*/

               /*//遍历方式2
               for (int i = 0; i < list.size(); i++) {
                       String s = (String) list.get(i);
                       System.out.println(s);
               }*/

               //遍历方式3
               ListIterator li = list.listIterator();
               while(li.hasNext()){
                       String s = (String) li.next();
                       System.out.println(s);
               }

               //遍历方式4
               //逆向遍历(前提,需先进行正向遍历)
//             ListIterator li = list.listIterator();
               while(li.hasPrevious()){
                       String s = (String) li.previous();
                       System.out.println(s);
               }

题目:
写一个类MyLinked,实现双向循环链表
Node head(链表头)
size(元素个数)

Boolean add(E e):
boolean remove(E e):
int Size():

Node (节点,内部类)
    element(元素)
    next(下一个节点)
    prev(上一个节点)

//自定义双向循环链表
class MyLinked<E>{

        //链表头
        private Node head;

        //链表中的元素个数
        private int size;

        //添加元素
        public boolean add(E e){
               Node node = new Node();//创建节点
               node.element = e;//给节点添加元素
               //判断是否是首节点
               if(head == null){
                       head = node;
                       head.prev = head;
                       head.next = head;
               }else{
                       head.prev.next = node;
                       node.next = head;
                       node.prev = head.prev;
                       head.prev = node;
               }
               size++;
               return true;              
        }


        //移除元素

        public boolean remove(E e){

               //判断链表是否为空
               if(size == 0){
                       return false;
               }
               Node node = head;
               do{
                   //判断当前节点内是否存在需要删除的内容
                   if(node.element.equals(e)){
                           node.prev.next = node.next;
                           node.next.prev = node.prev;
                           size--;
                           if(size == 0){
                               head = null;
                           }
                           return true;
                       }else{
                           node = node.next;
                       }
               }while(node != head);
               return false; 
        }

        //获取集合大小
        public int size(){
               return size;
        }

        //是否包含指定元素
        public boolean contains(E e){
               Node node = head;
               do{
                       if(node.element.equals(e)){
                               return true;
                       }
                       node = node.next;
               }while(node != head);
               return false;
        }

        //toString
        public String toString(){
               StringBuilder sb = new StringBuilder();
               sb.append("[");
               Node node = head;
               do{
                       sb.append(node.element).append(",");
                       node = node.next;
               }while(node != head);
               int index = sb.lastIndexOf(",");
               sb.replace(index, index+1, "]");
               return sb.toString();
        }

        class Node{
               //当前节点内的元素
               private E element;
               //上一个节点
               private Node prev;
               //下一个节点
               private Node next;
        }
}

public class MyLinkedDemo {
        public static void main(String[] args) {
               MyLinked<String> ml = new MyLinked<String>();
               ml.add("hello");
               ml.add("world");
               ml.add("java");
               ml.add("world");
               System.out.println(ml);
               System.out.println(ml.size());
               System.out.println(ml.remove("java"));
               System.out.println(ml.size());
               System.out.println(ml);
        }
}



================输出结果=============

[hello,world,java,world]
4
true
3
[hello,world,world]

9、队列Queue(接口)

队列需要满足先进先出的原则
队列的遍历是一次性的,想要获取队列里面某个元素,需要先将队列中该元素之前的所有元素获取到,才能访问该元素
成员方法
    boolean offer(E e):向队列末尾添加元素(入队)
    E poll():获取并删除队列的首元素(出队)
    E peek():获取队列的首元素

10、双端队列Deque

队列两端都可以进出
当使用双端队列如果只从一侧操作,就形成了一种存储模式(先进后出)
从一侧操作,入队出队方法
boolean push(E e):入队
E pop():出队

注:pop()与poll()区别?
poll是队列数据结构实现类的方法,从队首获取元素,同时获取的这个元素将从原队列删除,当队列中没有元素时,调用该方法返回hull;pop是栈结构的实现类的方法,表示返回栈顶的元素,同时该元素从栈中删除,当栈中没有元素时,调用该方法会发生异常。

11、Set接口

继承Collection,元素无序唯一的

12、SortedSet接口

继承于Set保存有序的集合。

13、TreeSet

实现的是SortedSet接口,可以实现排序等功能,底层是红黑二叉树,不能添加值为null元素,元素唯一
排序方式:
1)自然排序(元素具有比较性)
    元素对应的类需要实现 Comparable接口
2)比较器排序(集合具有比较性)
    构造方法接收1个比较器Comparator
    TreeSet(Comparator c)

import java.util.TreeSet;

class Pig implements Comparable<Pig>{
        String name;
        int age;
        public Pig() {
               super();
        }
        public Pig(String name, int age) {
               super();
               this.name = name;
               this.age = age;
        }

        @Override
        public int hashCode() {
               final int prime = 31;
               int result = 1;
               result = prime * result + age;
               result = prime * result + ((name == null) ? 0 : name.hashCode());
               return result;
        }

        @Override
        public boolean equals(Object obj) {
               if (this == obj)
                       return true;
               if (obj == null)
                       return false;
               if (getClass() != obj.getClass())
                       return false;
               Pig other = (Pig) obj;
               if (age != other.age)
                       return false;
               if (name == null) {
                       if (other.name != null)
                               return false;
               } else if (!name.equals(other.name))
                       return false;
               return true;
        }

        @Override
        public String toString() {
               return "Pig [age=" + age + ", name=" + name + "]";
        }

        @Override
        public int compareTo(Pig p) {
               //先按年龄的由小到大进行排序
               int num = this.age - p.age;
               //如果年龄相同,则按姓名的的字典顺序排序
               int num2 = num==0?this.name.compareTo(p.name):num;
               return num2;
        }

}

public class TreeSetDemo {
        public static void main(String[] args) {
               /*TreeSet<Integer> ts = new TreeSet<Integer>();
               ts.add(30);
               ts.add(50);
               ts.add(10);
               ts.add(20);
               ts.add(40);
               ts.add(30);             
               for (Integer i : ts) {
                       System.out.println(i);
               }*/

               /*
                10
                20
                30
                40
                50
                  */
              
               Pig p1 = new Pig("xiaohei",2);
               Pig p2 = new Pig("xiaobai",1);
               Pig p3 = new Pig("dazhuang",4);
               Pig p4 = new Pig("dabai",5);
               Pig p5 = new Pig("dahei",3);
               Pig p6 = new Pig("xiaojie",3);
               TreeSet<Pig> ts = new TreeSet<Pig>();
               ts.add(p1);
               ts.add(p2);
               ts.add(p3);
               ts.add(p4);
               ts.add(p5);
               ts.add(p6);
               for (Pig pig : ts) {
                       System.out.println(pig);
               }

                /++++++
                Pig [age=1, name=xiaobai]
                Pig [age=2, name=xiaohei]
                Pig [age=3, name=dahei]
                Pig [age=3, name=xiaojie]
                Pig [age=4, name=dazhuang]
                Pig [age=5, name=dabai]
                *******/
        }
}
import java.util.Comparator;
import java.util.TreeSet;
//比较器
class Chicken{
        String name;
        int age;
        public Chicken() {
              super();

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

        @Override
        public String toString() {
               return "Chicken [age=" + age + ", name=" + name + "]";
        }

        @Override
        public int hashCode() {
               final int prime = 31;
               int result = 1;
               result = prime * result + age;
               result = prime * result + ((name == null) ? 0 : name.hashCode());
               return result;
        }

        @Override
        public boolean equals(Object obj) {
               if (this == obj)
                      return true;
               if (obj == null)
                       return false;
               if (getClass() != obj.getClass())
                       return false;
               Chicken other = (Chicken) obj;
               if (age != other.age)
                       return false;
               if (name == null) {
                       if (other.name != null)
                               return false;
               } else if (!name.equals(other.name))
                       return false;
               return true;
        }
}

public class TreeSetDemo02 {
        public static void main(String[] args) {
               Chicken c = new Chicken("xiaohuang",2);
               Chicken c2 = new Chicken("xiaohua",5);
               Chicken c3 = new Chicken("aohuag",3);
               Chicken c4 = new Chicken("xiaoang",4);
               Chicken c5 = new Chicken("aohuang",1);
               Chicken c6 = new Chicken("xiang",3);
               TreeSet<Chicken> ts = new TreeSet<Chicken>(new Comparator<Chicken>() {

                       @Override
                       public int compare(Chicken c1, Chicken c2) {
                               //先按年龄由大到小排序
                               int num = c2.age - c1.age;
                               //如果年龄相同,再按字典顺序比较姓名
                               int num2 = num==0?c1.name.compareTo(c2.name):num;
                               return num2;
                       }

               });
               ts.add(c);
               ts.add(c2);
               ts.add(c3);
               ts.add(c4);
               ts.add(c5);
               ts.add(c6);
               for (Chicken chicken : ts) {
                       System.out.println(chicken);
               }
        }
}

============输出结果==================

Chicken [age=5, name=xiaohua]
Chicken [age=4, name=xiaoang]
Chicken [age=3, name=aohuag]
Chicken [age=3, name=xiang]
Chicken [age=2, name=xiaohuang]
Chicken [age=1, name=aohuang]

14、HashSet类

实现Set接口,元素是无序且唯一的,允许最多出现一个值为null的元素。
底层是哈希表(元素是链表的数组,结合了数组和链表的优点)
   (面试题)如何保证唯一性?
    两个对象hash不同,这两个元素一定不等;反之,不能确定。
    拿添加元素和同一分区内的所有元素进行比较,判断该分区内是否已经添加了该元素
        比较规则:(分步骤)
            ①先比较两个对象的hash是否相同:如果新添加的元素和分区内所有元素的hash都不相同,那么添加该元素;
            ②如果新添加的元素和分区内某个元素的hash相同,这时候就看它们的地址值是否相同:
            ③如果不同,还要通过equals比较这两个对象是否相同:如果相等,不能添加;如果不等,添加新元素
              总结为一句话:
                只有所有分区内元素和新元素的地址值不同且通过equals比较,不等,添加新元素
两个对象hash不同,这两个对象一定不等,反之,不能确定。拿添加元素和同一个分区内的所有元素进行比较,判断该分区内
for(Entry<K,V> e = table[i]; e != null; e = e.next){//获取分区内所有元素
    if (e.hash == hash && ((k = e.key) == key || key.equals(k))){
        //之前的集合中已经存在将要添加的元素
        V oldValue = e.value;
        e.value = value;
        e.recordAccess(this);
        return oldValue;
    }
}
//添加元素
 modCount++;
 addEntry(hash, key, value, i);
 return null;
 
 阐述Hash的过程
 1)获取两个对象的hash
     hash = e.hashCode();
     hash = hash^hash>>>16;
 2)定位桶(元素无序原因)
     i = hash&(length-1)
 3)判断桶元素
     3.1桶 = null
         添加链表的头元素
     3.2桶 != null
         添加链表的其他元素

15、LinkedHashSet

继承HashSet类,元素是有序唯一的,只允许出现一个null值
有序是由链表保证,唯一是由哈希表保证

Set和List的区别

  • 1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
  • 2. Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>
  • 3. List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector>

16、Map(接口)

存储的是键值对、将键映射映射到值
键不可以重复,值可以重复,每一键只能映射到一个值 ,两个键可以映射两个相同的值

成员方法(口诀“1 2 3 5”)

添加功能:
V put(k v):添加键值对
删除功能:
void clear():清空
V remove(k):通过键删除对象的键值对
判断功能:
containsKey(k):是否包含指定的键
containsValue(v):是否包含指定的值
isEmpty():是否是空
获取功能:
size():键值对个数
v get (k):通过键获取值
Set<k> keySet():获取所有键组成的集合  【有序】
collection<v> values():获取所有值组成的集合【无序,用的是XX父类】
Set<Map.Entry<K.V>> entrySet():获取键值对组成的集合

17、Map.Entry

描述在一个Map中的一个元素(键/值对)。是一个Map的内部类。

18、HashMap

实现Map接口,允许出现一个null键和多个null值

HashMap和Hashtable的区别【面试题】
HashMap:线程不安全,不同步,效率高:允许出现null键和null值
Hashtable:线程安全,同步,效率低:不允许出现null键和null值

19、Dictionary

Dictionary 类是一个抽象类,用来存储键/值对,作用和Map类相似。

20、Hashtable

Hashtable 是 Dictionary(字典) 类的子类,同时实现了Map接口,位于 java.util 包中。

21、Properties

Properties 继承于 Hashtable,表示一个持久的属性集,属性列表中每个键及其对应值都是一个字符串。

22、LinkedHashMap(HashMap、【无序】)

继承HashMap,键值对是有序的

23、SortedMap(接口)

继承于 Map,使 Key 保持在升序排列。

24、TreeMap

实现了SortedMap接口,元素可以根据键进行排序,元素具有唯一性
排序方式
1)自然排序(元素具有比较性)
    元素对应实现的类要实现Comparable接口    
2)比较器排序(集合具有比较性)
    构造方法接受1个比较器Comparator
    TreeSet(Comparator c)

遍历 Map

import java.util.*;
 
public class Test{
     public static void main(String[] args) {
      Map<String, String> map = new HashMap<String, String>();
      map.put("1", "value1");
      map.put("2", "value2");
      map.put("3", "value3");
      
      //第一种:普遍使用,二次取值
      System.out.println("通过Map.keySet遍历key和value:");
      for (String key : map.keySet()) {
       System.out.println("key= "+ key + " and value= " + map.get(key));
      }
      
      //第二种
      System.out.println("通过Map.entrySet使用iterator遍历key和value:");
      Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
      while (it.hasNext()) {
       Map.Entry<String, String> entry = it.next();
       System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
      }
      
      //第三种:推荐,尤其是容量大时
      System.out.println("通过Map.entrySet遍历key和value");
      for (Map.Entry<String, String> entry : map.entrySet()) {
       System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
      }
    
      //第四种
      System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
      for (String v : map.values()) {
       System.out.println("value= " + v);
      }
     }
}

25、Collections

针对集合进行操作的工具类
常见方法:
sort(List<T> list):集合排序,默认自然排序
sort(List<T> list,Comparator<T> c):根据比较器进行排序
binarySearch(List<T> list,T t):二分法查找
reverse(Lisr<T> list):反转
shuffle(Lisr<T> list):随机置换
max(Collection c):获取最大值

案例:斗地主(一副牌实现洗牌、发牌、给玩家手中的牌进行排序)

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.TreeSet;

//三人斗地主,洗牌发牌
public class PokerDemo {
	public static void main(String[] args) {
		//牌盒
		HashMap<Integer,String> pokers = new HashMap<Integer,String>();
		//牌号
		List<Integer> list = new ArrayList<Integer>();
		
		for (int i = 0; i < 54; i++) {
			list.add(i);
		}
		//花色
		String[] colors = {"黑桃","红桃","梅花","方片"};
		//点数
		String[] nums = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
		String poker = null;
		int k=0;
		for (String num : nums) {
			for (String color : colors) {
				poker = color+num;//牌
				pokers.put(k, poker);
				k++;
			}
		}
		//放入小大王
		pokers.put(52,"小王");
		pokers.put(53,"大王");
		
		//洗牌
		Collections.shuffle(list);
		
		//玩家和底牌的牌盒
		/*List<Integer> player01 = new ArrayList<Integer>();
		List<Integer> player02 = new ArrayList<Integer>();
		List<Integer> player03 = new ArrayList<Integer>();
		List<Integer> diPai = new ArrayList<Integer>(); */
		TreeSet<Integer> player01 = new TreeSet<Integer>();
		TreeSet<Integer> player02 = new TreeSet<Integer>();
		TreeSet<Integer> player03 = new TreeSet<Integer>();
		TreeSet<Integer> diPai = new TreeSet<Integer>();
		
		int i = 0;
		for (int pai : list) {
			if(i>=list.size()-3)
				diPai.add(pai);
			else if(i%3==0)
				player01.add(pai);
			else if(i%3==1)
				player02.add(pai);
			else if(i%3==2)
				player03.add(pai);
			i++;
		}
		
		//对玩家(底牌)的牌按从小到大排序
		/*Collections.sort(player01);
		Collections.sort(player02);
		Collections.sort(player03);
		Collections.sort(diPai);*/
		
		System.out.println("玩家1:");
		for (int p1 : player01) {
			System.out.print(pokers.get(p1)+"\t");
		}
		System.out.println("\n玩家2:");
		for (int p2 : player02) {
			System.out.print(pokers.get(p2)+"\t");
		}
		System.out.println("\n玩家3:");
		for (int p3 : player03) {
			System.out.print(pokers.get(p3)+"\t");
		}
		System.out.println("\n底牌:");
		for (int d : diPai) {
			System.out.print(pokers.get(d)+"\t");
		}
	}
}


=======================输出结果===================================
玩家1:
方片3	红桃4	黑桃5	梅花5	方片5	梅花6	黑桃8	梅花8	方片8	黑桃9	红桃9	红桃Q	方片Q	红桃K	梅花K	红桃2	大王	
玩家2:
红桃3	方片4	红桃6	黑桃7	红桃7	方片7	红桃8	梅花9	方片9	黑桃10	红桃10	黑桃J	红桃J	方片K	黑桃A	黑桃2	梅花2	
玩家3:
黑桃3	黑桃4	梅花4	红桃5	黑桃6	方片6	梅花7	梅花10	方片10	梅花J	方片J	黑桃Q	梅花Q	黑桃K	红桃A	方片2	小王	
底牌:
梅花3	梅花A	方片A	

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Superme_No1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值