• 集合框架


    集合框架总图:

    一、ArrayList

    为什么要使用?

    存放多个对象也可以使用数组,但是定义数组有局限性,例如先声明个长度为20的数组,如果存10个就浪费了空间,存25个又不够。所以引入容器,ArrayList就是一种常见的容器,容器的容量会随着存放的对象自动增多。

    常用方法

    例子:

    public class ArrayListTest {
    
        public static void main(String[] args) {
            //泛型,list只能存string类型
            //下面这样写可以存各种类型
            //ArrayList list1 = new ArrayList();
            ArrayList<String> list = new ArrayList<String>();
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
            System.out.println(list);
            System.out.println("之前的长度:"+list.size());
            list.add("ddd");
            
            System.out.println("新添加一个元素后的长度:"+list.size());
            System.out.println(list);
            //contains判断容器中是否有某元素
            System.out.println("是否存在aaa:"+list.contains("aaa"));
            //get获得指定位置的元素
            System.out.println("第2个元素是:"+list.get(1));
            //set替换某位置的元素
            System.out.println("拿AAA替换第一个元素:"+list.set(0, "AAA"));
            System.out.println(list);
            //转化为数组,如果要转换为一个string数组,
            //那么需要传递一个string数组类型的对象给toArray(),
            //这样toArray方法才知道,你希望转换为哪种类型的数组,否则只能转换为Object数组
            String []arr = new String[list.size()];
            arr=(String[]) list.toArray(new String[] {});
            for(String str:arr) {
                System.out.println("转化成数组:"+str);
            }
            //清空list
            list.clear();
            System.out.println(list);
    
        }
    
    }

    泛型

    不指定泛型的容器,可以存放任何类型的元素
    指定了泛型的容器,只能存放指定类型的元素以及其子类,如上面代码的 ArrayList<String> list,只能存放String类型

    三种遍历集合的方法

    使用for循环

    方便操作集合中相关元素

    使用迭代器iterator

    增强型for循环

    使用增强型for循环可以非常方便的遍历ArrayList中的元素,这是很多开发人员的首选

    不过增强型for循环也有不足:
    无法用来进行ArrayList的初始化
    无法得知当前是第几个元素了,当需要只打印单数元素的时候,就做不到了。 必须再自定下标变量。

    代码

    public class Test {
    
        public static void main(String[] args) {
            ArrayList<Integer> al = new ArrayList<>();
            for(int i=0;i<10;i++) {
                al.add(i);
            }
            System.out.println("----------for循环遍历------------");
            for(int i=0;i<al.size();i++) {
                /*for循环遍历的好处,可以操作相关元素
                 * if((i+1)%8==0) {
                    al.remove(i);
                    continue;
                }*/
                System.out.print(al.get(i)+",");
            }
            System.out.println();
            System.out.println("----------迭代器遍历------------");
            Iterator<Integer> it = al.iterator();
            while(it.hasNext()) {
                System.out.print(it.next()+",");
            }
            System.out.println();
            System.out.println("----------foreach循环遍历------------");
            for(Integer i:al) {
                System.out.print(i+",");
            }
            }
    }

    二、LinkedList

    LinkedList也实现了List接口,像add(),get()这些List的方法也可以使用。

     Deque

    特别的是 它实现了双向链表Deque,可以很方便的在头和尾进行操作;

    常用方法:

    addFirst()在最前面插入元素,addLast()在最后面插入元素,

    getFirst(),getLast查看头部和尾部元素,

    removeFirst(),removeLast()移除头部尾部元素

     Queue

    还实现了Queue(队列)接口,队列的特点是先进先出(FIFO)

    常用方法:

    offer() 在最后面添加元素

    peek()查看第一个元素

    pool()取出第一个元素

    代码

    public class LinkedListTest {
    
        public static void main(String[] args) {
            LinkedList<Integer> ll = new LinkedList<Integer>();
            //双向链表deque
            Deque<Integer> d = new LinkedList<Integer>();
            //队列queue
            Queue<Integer> q = new LinkedList<Integer>();
            //初始化
            for(int i=1;i<10;i++) {
                ll.add(i);
                d.add(i);
                q.add(i);
            }
            /*
             * Deque的相关方法
             * 
             * addLast
             * getFirst
             * removeFirst
             * 
             */
            System.out.println("deque初始值"+d);
            //尾部添加10
            d.addLast(10);
            System.out.println("尾部添加:"+d);
            //头部添加0
            d.addFirst(0);
            System.out.println("头部添加:"+d);
            //查看第一个
            System.out.println("查看头部:"+d.getFirst());
            //取出最后一个
            d.removeLast();
            System.out.println("取出最后一个:"+d);
            /*
             * Queue队列的相关方法
             * offer放置队尾
             * poll取出队列第一个元素
             * peek查看队列第一个元素
             */
            System.out.println("queue初始值:"+q);
            q.offer(10);
            System.out.println("队尾添加后:"+q);
            q.poll();
            System.out.println("使用poll去掉队首:"+q);
            System.out.println("使用peek查看队首:"+q.peek());

    结果:

     stack

    stack栈是先进后出(FILO),利用Deque实现自定义Stack

    先定义接口Stack

    public interface Stack {
        //把元素推入到最后位置
        public void push(Integer i);
        //把最后一个元素取出来
        public Integer pull();
        //查看最后一个元素
        public Integer peek();
        }

    自定义MyStack实现接口

    public class Mystack implements Stack {
        Deque<Integer> dq = new LinkedList<Integer>();
       public void push(Integer i) {
            // 入栈,到最底部
            dq.addLast(i);
        }

    public Integer pull() { // 取出最后一个元素 return dq.removeLast(); } public Integer peek() { // 查看最后一个元素 return dq.getFirst(); } }

    三、二叉树

    建立二叉树:基本思想 小的在左边,大的在右边

    public class Node {
        //左子节点
        public Node leftNode;
        //右子节点
        public Node rightNode;
        //
        public Object value;
        
        public void add(Object o) {
            //如果当前节点值为空
            if(value==null) {
                value=o;
            }
            else {//值小于等于根的值放入左节点
                if((int)o<=(int)value) {
                    if(leftNode==null) {
                    leftNode = new Node();}
                    
                    leftNode.add(o);
                    
                }else {//值大于根的值
                    if(rightNode==null) 
                    {rightNode = new Node();}
                    
                    rightNode.add(o);
                  }  
                }
            }
        }

    二叉树的遍历:前序遍历:根左右

                             中序遍历:左根右

                             后序遍历:左右根

    接下来是中序遍历,顺便还能排序,这就是二叉树排序

    public List<Object> values() {
             //中序遍历二叉树
            List<Object> al = new ArrayList<>(); 
            //左节点
            if(leftNode!=null)
                al.addAll(leftNode.values());
            //当前节点
            al.add(value);
            //右节点
            if(rightNode!=null)
                al.addAll(rightNode.values());
               return al;
        }

    四、HashMap

    HashMap的存储方式是键值对的方式,键不能重复,值可以重复

    public class HashMapTest {
    
        public static void main(String[] args) {
            HashMap<String, String> hm = new HashMap<>();
            hm.put("name", "tom");
            hm.put("age", "18");
            hm.put("sex", "man");
            System.out.println(hm.get("name"));
    
        }
    
    }

    3种遍历方式,分别使用foreach和迭代器遍历

    package com.yyt.pojo;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    import java.util.concurrent.atomic.AtomicStampedReference;
    
    import javax.activation.MailcapCommandMap;
    
    public class YeYangTao {
    
        public static void main(String[] args) {
            HashMap<String, String> map = new HashMap<>();
            map.put("001", "yyt1");
            map.put("002", "yyt2");
            map.put("003", "yyt3");
            //ketSet遍历 foreach
            for(Object o:map.keySet()) {
                System.out.println(o);
            }
            //ketSet遍历 迭代器
            Iterator it1 =  map.keySet().iterator();
            while(it1.hasNext()) {
                System.out.println(it1.next());
            }
            //values foreach
            for(Object o:map.values()) {
                System.out.println(o);
            }
            //values 迭代器
            Iterator it2 = map.values().iterator();
            while (it2.hasNext()) {
                System.out.println(it2.next());
                
            }
            //entry foreach
            Set<Entry<String, String>> entry = map.entrySet();
            for(Entry<String, String> e:entry) {
                    System.out.println(e.getKey()+","+e.getValue());
            }
            //entry 迭代器
            Iterator<Entry<String, String>> it = map.entrySet().iterator();
            while(it.hasNext()) {
                Map.Entry<String, String> entry1 = it.next();
                System.out.println(entry1.getKey()+","+entry1.getValue());
            }
            
            
    
        }
    
    }

    五、HashSet

    无序,不可重复。其实它就是HashMap中的key。

    它没有顺序,不能通过get()来获取元素

    所以遍历用增强型for循环和Iterator迭代器

    接下来用HashSet来解决一个问题:

    问题:

    创建一个长度是100的字符串数组
    使用长度是2的随机字符填充该字符串数组
    统计这个字符串数组里重复的字符串有多少种并输出重复值


    思路:定义两个HashSet,利用第一个插入随机字符串数组,但是HashSet不允许重复,所以第二次遇到重复的则会插入失败,用第二个HashSet保存插入失败的元素,最后只需要统计第二个HashSet的长度和其中元素便找到了有多少种重复和重复值是什么。

    代码:

    public class HashSetTest {
        
    
        public static void main(String[] args) {
            //获取100个长度为2的随机字符串
            String s[] = new String[100];
            for(int i=0;i<s.length;i++) {
                s[i] = randomStr(2);
            }
            System.out.println("初始化字符串数组为:");
            for(int i=0;i<s.length;i++) {
                System.out.print(s[i] +" ");
                if(i%10==9)
                    System.out.println();
                }
            HashSet<String> repeat =new HashSet<String>();
            HashSet<String> sets =new HashSet<String>();
            for(String str:s) {
                if(!sets.add(str)) {//当之前有重复值的时候,第二次会插入失败
                    repeat.add(str);//将插入失败的值保存,也就是重复值
                }
            }
            System.out.println("重复的有"+repeat.size()+"个");
            for(String str:repeat) {
                System.out.println(str);
            }
     }
        //获取随机字符串
        public static String randomStr(int length) { 
            Random r = new Random();
            int i;
            String s = "qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM1234567890";
            char sa[]=new char[length];
            for(int j=0;j<length;j++) {
                //26个大写字母,26个小写字母,10位数字
                 i = r.nextInt(26+26+10-1);
                sa[j]=s.charAt(i);
            }
            return new String(sa);
            }
    
    }

     六、关系和区别

    1、collection与collections

    collection是一个接口,是Set,List,Queue的接口

    collections是一个类,容器的工具类

         常用方法

       

    2、ArrayList与HashSet

    ArrayList有序,HashSet无序

    List中可以重复,Set中不能重复

    3、ArrayList与LinkedList

    都可以重复

    ArrayList插入数据慢,删除数据慢,但它是顺序结构,定位快

    LinkedList插入、删除数据快,但它是链表结构,定位慢

    4、线程安全的与线程不安全的

    Vector与ArrayList区别

    HashTable与HashMap区别

    都是前者是线程安全的类。

  • 相关阅读:
    用汇编的眼光看c++(之模板函数) 四
    从B树、B+树、B*树谈到R 树 四
    how to locate dll in native c++ world / dotnet world?
    GAC和sidebyside
    ARM VS Intel
    关于dotnet下的encoding
    synchronization objects for interprocess synchronization and multithreadiing
    [remote debug]WinDBG 技巧: 如何用WinDBG远程调试程序
    [tip]transparent bmp
    Review: functor / function object
  • 原文地址:https://www.cnblogs.com/yeyangtao/p/10825917.html
Copyright © 2020-2023  润新知