【课堂笔记分享】linkedlist、二叉树、hashmap

LinkedList

  • 序列分先进先出FIFO,先进后出FILO
  • FIFO在Java中又叫Queue 队列
  • FILO在Java中又叫Stack 栈

LinkedList 与 List接口

  • 与ArrayList一样,LinkedList也实现了List接口,诸如add,remove,contains等等方法。 详细使用,请参考ArrayList 常用方法,在此不作赘述。

  • 接下来要讲的是LinkedList的一些特别的地方

双向链表 - Deque

  • 除了实现了List接口外,LinkedList还实现了双向链表结构Deque,可以很方便的在头尾插入删除数据

  • 什么是链表结构: 与数组结构相比较,数组结构,就好像是电影院,每个位置都有标示,每个位置之间的间隔都是一样的。
    而链表就相当于佛珠,每个珠子,只连接前一个和后一个,不用关心除此之外的其他佛珠在哪里。
    在这里插入图片描述

package collection;
 
import java.util.LinkedList;
 
import charactor.Hero;
 
public class TestCollection {
 
    public static void main(String[] args) {
         
        //LinkedList是一个双向链表结构的list
        LinkedList<Hero> ll =new LinkedList<Hero>();
         
        //所以可以很方便的在头部和尾部插入数据
        //在最后插入新的英雄
        ll.addLast(new Hero("hero1"));
        ll.addLast(new Hero("hero2"));
        ll.addLast(new Hero("hero3"));
        System.out.println(ll);
         
        //在最前面插入新的英雄
        ll.addFirst(new Hero("heroX"));
        System.out.println(ll);
         
        //查看最前面的英雄
        System.out.println(ll.getFirst());
        //查看最后面的英雄
        System.out.println(ll.getLast());
         
        //查看不会导致英雄被删除
        System.out.println(ll);
        //取出最前面的英雄
        System.out.println(ll.removeFirst());
         
        //取出最后面的英雄
        System.out.println(ll.removeLast());
         
        //取出会导致英雄被删除
        System.out.println(ll);
         
    }
      
}

队列 - Queue

  • LinkedList 除了实现了List和Deque外,还实现了Queue接口(队列)。
  • Queue是先进先出队列 FIFO,常用方法:
  • offer在最后添加元素
  • poll取出第一个元素
  • peek 查看第一个元素
  • package collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
  
import charactor.Hero;
  
public class TestCollection {
  
    public static void main(String[] args) {
        //和ArrayList一样,LinkedList也实现了List接口
        List ll =new LinkedList<Hero>();
          
        //所不同的是LinkedList还实现了Deque,进而又实现了Queue这个接口
        //Queue代表FIFO 先进先出的队列
        Queue<Hero> q= new LinkedList<Hero>();
          
        //加在队列的最后面
        System.out.print("初始化队列:\t");
        q.offer(new Hero("Hero1"));
        q.offer(new Hero("Hero2"));
        q.offer(new Hero("Hero3"));
        q.offer(new Hero("Hero4"));
          
        System.out.println(q);
        System.out.print("把第一个元素取poll()出来:\t");
        //取出第一个Hero,FIFO 先进先出
        Hero h = q.poll();
        System.out.println(h);
        System.out.print("取出第一个元素之后的队列:\t");
        System.out.println(q);
          
        //把第一个拿出来看一看,但是不取出来
        h=q.peek();
        System.out.print("查看peek()第一个元素:\t");
        System.out.println(h);
        System.out.print("查看并不会导致第一个元素被取出来:\t");
        System.out.println(q);
          
    }
       
}

使用LinkedList实现Stack栈

  • 与FIFO(先入先出的)队列类似的一种数据结构是FILO先入后出栈Stack
  • 根据接口Stack :
  • 实现类:MyStack
public class MyStack implements Stack
  • 并向这个栈中,压入5个英雄,接着弹出5个英雄
package collection;
 
import charactor.Hero;
 
public interface Stack {
 
    //把英雄推入到最后位置
    public void push(Hero h);
    //把最后一个英雄取出来
    public Hero pull();
    //查看最后一个英雄
    public Hero peek();
}
package collection;
   
import java.util.LinkedList;
   
import charactor.Hero;
   
public class MyStack implements Stack{
   
    LinkedList<Hero> heros = new LinkedList<Hero>();
       
    @Override
    public void push(Hero h) {
        heros.addLast(h);
    }
   
    @Override
    public Hero pull() {
        return heros.removeLast();
    }
   
    @Override
    public Hero peek() {
        return heros.getLast();
    }
       
    public static void main(String[] args) {
           
        MyStack heroStack = new MyStack();
        for (int i = 0; i < 5; i++) {
            Hero h = new Hero("hero name " + i);
            System.out.println("压入 hero:" + h);
            heroStack.push(h);
        }
        for (int i = 0; i < 5; i++) {
            Hero h =heroStack.pull();
            System.out.println("弹出 hero" + h);
        }
    }
   
}

二叉树

二叉树概念

  • 二叉树由各种节点组成
  • 二叉树特点:
  • 每个节点都可以有左子节点,右子节点
  • 每一个节点都有一个值
    在这里插入图片描述
package collection;
 
public class Node {
    // 左子节点
    public Node leftNode;
    // 右子节点
    public Node rightNode;
    // 值
    public Object value;
}

二叉树排序-插入数据

  • 假设通过二叉树对如下10个随机数进行排序

  • 67,7,30,73,10,0,78,81,10,74

  • 排序的第一个步骤是把数据插入到该二叉树中

  • 插入基本逻辑是,小、相同的放左边,大的放右边

    1. 67 放在根节点

    2. 7 比 67小,放在67的左节点

    3. 30 比67 小,找到67的左节点7,30比7大,就放在7的右节点

    4. 73 比67大, 放在67的右节点

    5. 10 比 67小,找到67的左节点7,10比7大,找到7的右节点30,10比30小,放在30的左节点。

  • 10比67小,找到67的左节点7,10比7大,找到7的右节点30,10比30小,找到30的左节点10,10和10一样大,放在左边
    在这里插入图片描述

package collection;
  
public class Node {
    // 左子节点
    public Node leftNode;
    // 右子节点
    public Node rightNode;
  
    // 值
    public Object value;
  
    // 插入 数据
    public void add(Object v) {
        // 如果当前节点没有值,就把数据放在当前节点上
        if (null == value)
            value = v;
  
        // 如果当前节点有值,就进行判断,新增的值与当前值的大小关系
        else {
            // 新增的值,比当前值小或者相同
             
            if ((Integer) v -((Integer)value) <= 0) {
                if (null == leftNode)
                    leftNode = new Node();
                leftNode.add(v);
            }
            // 新增的值,比当前值大
            else {
                if (null == rightNode)
                    rightNode = new Node();
                rightNode.add(v);
            }
  
        }
  
    }
  
    public static void main(String[] args) {
  
        int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };
  
        Node roots = new Node();
        for (int number : randoms) {
            roots.add(number);
        }
  
    }
}

二叉树排序-遍历

  • 通过上一个步骤的插入行为,实际上,数据就已经排好序了。 接下来要做的是看,把这些已经排好序的数据,遍历成我们常用的List或者数组的形式
  • 二叉树的遍历分左序,中序,右序

1.左序即: 中间的数遍历后放在左边
2.中序即: 中间的数遍历后放在中间
3.右序即: 中间的数遍历后放在右边

  • 如图所见,我们希望遍历后的结果是从小到大的,所以应该采用中序遍历
    在这里插入图片描述
package collection;
 
import java.util.ArrayList;
import java.util.List;
 
public class Node {
    // 左子节点
    public Node leftNode;
    // 右子节点
    public Node rightNode;
  
    // 值
    public Object value;
  
    // 插入 数据
    public void add(Object v) {
        // 如果当前节点没有值,就把数据放在当前节点上
        if (null == value)
            value = v;
  
        // 如果当前节点有值,就进行判断,新增的值与当前值的大小关系
        else {
            // 新增的值,比当前值小或者相同
             
            if ((Integer) v -((Integer)value) <= 0) {
                if (null == leftNode)
                    leftNode = new Node();
                leftNode.add(v);
            }
            // 新增的值,比当前值大
            else {
                if (null == rightNode)
                    rightNode = new Node();
                rightNode.add(v);
            }
  
        }
  
    }
  
 // 中序遍历所有的节点
    public List<Object> values() {
        List<Object> values = new ArrayList<>();
  
        // 左节点的遍历结果
        if (null != leftNode)
            values.addAll(leftNode.values());
  
        // 当前节点
        values.add(value);
  
        // 右节点的遍历结果
        if (null != rightNode)
  
            values.addAll(rightNode.values());
  
        return values;
    }
  
    public static void main(String[] args) {
  
        int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };
  
        Node roots = new Node();
        for (int number : randoms) {
            roots.add(number);
        }
  
        System.out.println(roots.values());
  
    }
}

案例:英雄二叉树

根据上面的学习和理解,设计一个Hero二叉树,HeroNode. 
可以向这个英雄二叉树插入不同的Hero对象,并且按照Hero的血量倒排序。
 
随机生成10个Hero对象,每个Hero对象都有不同的血量值,插入这个HeroNode后,把排序结果打印出来。

- Hero

package charactor;
 
public class Hero {
    public String name;
    public float hp;
 
    public int damage;
 
    public Hero() {
 
    }
 
    public Hero(String name) {
 
        this.name = name;
    }
 
    public String toString() {
        return String.format("[name:%s hp:%.0f]%n", name,hp);
    }
 
}

- HeroNode

package collection;
 
import java.util.ArrayList;
import java.util.List;
 
import charactor.Hero;
 
public class HeroNode {
 
    public HeroNode leftHero;
 
    public HeroNode rightHero;
 
    // 声明为Hero类型
    public Hero value;
 
    public void add(Hero v) {
 
        if (null == value)
            value = v;
 
        else {
 
            // 如果新英雄血量,比本节点大,就放在左边
            if (v.hp > value.hp) {
                if (null == leftHero)
                    leftHero = new HeroNode();
                leftHero.add(v);
            }
 
            else {
                if (null == rightHero)
                    rightHero = new HeroNode();
                rightHero.add(v);
            }
 
        }
 
    }
 
    public List<Object> values() {
        List<Object> values = new ArrayList<>();
 
        if (null != leftHero)
            values.addAll(leftHero.values());
 
        values.add(value);
 
        if (null != rightHero)
 
            values.addAll(rightHero.values());
 
        return values;
    }
 
    public static void main(String[] args) {
 
        List<Hero> hs = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Hero h = new Hero();
            h.name = "hero " + i;
            h.hp = (float) (Math.random() * 900 + 100); // 100-1000的随机血量
            hs.add(h);
        }
        System.out.println("初始化10个Hero");
        System.out.println(hs);
 
        HeroNode heroTree = new HeroNode();
        for (Hero hero : hs) {
            heroTree.add(hero);
        }
        System.out.println("根据血量倒排序后的Hero");
        List<Object> treeSortedHeros = heroTree.values();
        System.out.println(treeSortedHeros);
 
    }
}

- 创建4万个随机数,然后用分别用冒泡法,选择法,二叉树3种排序算法进行排序,比较哪种更快

package collection;
 
import java.util.Arrays;
import java.util.List;
 
public class SortCompare {
 
    public static void main(String[] args) {
        //初始化随机数
        int total = 40000;
        System.out.println("初始化一个长度是"+total+"的随机数字的数组");
        int[] originalNumbers = new int[total];
        for (int i = 0; i < originalNumbers.length; i++) {
            originalNumbers[i] = (int)(Math.random()*total);
        }
        System.out.println("初始化完毕");
        System.out.println("接下来分别用3种算法进行排序");
         
        //从初始化了的随机数组复制过来,以保证,每一种排序算法的目标数组,都是一样的
        int[] use4sort;
         
        use4sort= Arrays.copyOf(originalNumbers, originalNumbers.length);
        int[] sortedNumbersBySelection= performance(new SelectionSort(use4sort),"选择法");
         
        use4sort= Arrays.copyOf(originalNumbers, originalNumbers.length);
        int[] sortedNumbersByBubbling=performance(new BubblingSort(use4sort),"冒泡法");
         
        use4sort= Arrays.copyOf(originalNumbers, originalNumbers.length);
        int[] sortedNumbersByTree=performance(new TreeSort(use4sort),"二叉树");
         
        System.out.println("查看排序结果,是否是不同的数组对象");
        System.out.println(sortedNumbersBySelection);
        System.out.println(sortedNumbersByBubbling);
        System.out.println(sortedNumbersByTree);
         
        System.out.println("查看排序结果,内容是否相同");
        System.out.println("比较 选择法 和 冒泡法  排序结果:");
        System.out.println(Arrays.equals(sortedNumbersBySelection, sortedNumbersByBubbling));
        System.out.println("比较 选择法 和 二叉树  排序结果:");
        System.out.println(Arrays.equals(sortedNumbersBySelection, sortedNumbersByTree));
         
    }
     
    interface Sort{
        void sort();
        int[] values();
    }
     
    static class SelectionSort implements Sort{
 
        int numbers[];
        SelectionSort(int [] numbers){
            this.numbers = numbers;
        }
         
        @Override
        public void sort() {
            for (int j = 0; j < numbers.length-1; j++) {
                for (int i = j+1; i < numbers.length; i++) {
                    if(numbers[i]<numbers[j]){  
                        int temp = numbers[j];
                        numbers[j] = numbers[i];
                        numbers[i] = temp;
                    }
                }
            }
        }
 
        @Override
        public int[] values() {
            // TODO Auto-generated method stub
            return numbers;
        }
         
    }
     
    static class BubblingSort implements Sort{
        int numbers[];
        BubblingSort(int [] numbers){
            this.numbers = numbers;
        }
        @Override
        public void sort() {
            for (int j = 0; j < numbers.length; j++) {
                for (int i = 0; i < numbers.length-j-1; i++) {
                    if(numbers[i]>numbers[i+1]){  
                        int temp = numbers[i];
                        numbers[i] = numbers[i+1];
                        numbers[i+1] = temp;
                    }
                }
            }
        }
        @Override
        public int[] values() {
            // TODO Auto-generated method stub
            return numbers;
        }
         
    }
     
    static class TreeSort implements Sort{
        int numbers[];
        Node n;
         
        TreeSort(int [] numbers){
            n =new Node();
            this.numbers = numbers;
        }
        @Override
        public void sort() {
         
            for (int i : numbers) {
                n.add(i);
            }
        }
        @Override
        public int[] values() {
            List<Object> list = n.values();
            int sortedNumbers[] = new int[list.size()];
            for (int i = 0; i < sortedNumbers.length; i++) {
                sortedNumbers[i] = Integer.parseInt(list.get(i).toString());
            }
            return sortedNumbers;
        }
    }
 
    private static int[] performance(Sort algorithm, String type) {
        long start = System.currentTimeMillis();
        algorithm.sort();
        int sortedNumbers[] = algorithm.values();
        long end = System.currentTimeMillis();
        System.out.printf("%s排序,一共耗时 %d 毫秒%n",type,end-start);
        return sortedNumbers;
    }
}

HashMap

HashMap的键值对

  • HashMap储存数据的方式是—— 键值对
package collection;
   
import java.util.HashMap;
   
public class TestCollection {
    public static void main(String[] args) {
        HashMap<String,String> dictionary = new HashMap<>();
        dictionary.put("adc", "物理英雄");
        dictionary.put("apc", "魔法英雄");
        dictionary.put("t", "坦克");
         
        System.out.println(dictionary.get("t"));
    }
}

键不能重复,值可以重复

  • 对于HashMap而言,key是唯一的,不可以重复的。
  • 所以,以相同的key 把不同的value插入到 Map中会导致旧元素被覆盖,只留下最后插入的元素。
  • 不过,同一个对象可以作为值插入到map中,只要对应的key不一样
package collection;
  
import java.util.HashMap;
  
import charactor.Hero;
  
public class TestCollection {
    public static void main(String[] args) {
        HashMap<String,Hero> heroMap = new HashMap<String,Hero>();
         
        heroMap.put("gareen", new Hero("gareen1"));
        System.out.println(heroMap);
         
        //key为gareen已经有value了,再以gareen作为key放入数据,会导致原英雄,被覆盖
        //不会增加新的元素到Map中
        heroMap.put("gareen", new Hero("gareen2"));
        System.out.println(heroMap);
         
        //清空map
        heroMap.clear();
        Hero gareen = new Hero("gareen");
         
        //同一个对象可以作为值插入到map中,只要对应的key不一样
        heroMap.put("hero1", gareen);
        heroMap.put("hero2", gareen);
         
        System.out.println(heroMap);
         
    }
}

- 查找内容性能比较

准备一个ArrayList其中存放3000000(三百万个)Hero对象,其名称是随机的,格式是hero-[4位随机数]
hero-3229
hero-6232
hero-9365
...
 
因为总数很大,所以几乎每种都有重复,把名字叫做 hero-5555的所有对象找出来
要求使用两种办法来寻找
1. 不使用HashMap,直接使用for循环找出来,并统计花费的时间
2. 借助HashMap,找出结果,并统计花费的时间
package collection;
  
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
  
import charactor.Hero;
  
public class TestCollection {
    public static void main(String[] args) {
        List<Hero> hs =new ArrayList<>();
        System.out.println("初始化开始");
        for (int i = 0; i < 3000000; i++) {
            Hero h = new Hero(   "hero-" + random());
            hs.add(h);
        }
        //名字作为key
        //名字相同的hero,放在一个List中,作为value
        HashMap<String,List<Hero>> heroMap =new HashMap();
        for (Hero h : hs) {
            List<Hero> list= heroMap.get( h.name);
            if(list==null){
                list = new ArrayList<>();
                heroMap.put(h.name, list);
            }
            list.add(h);
        }
          
        System.out.println("初始化结束");
        System.out.println("开始查找");
        findByIteration(hs);
        findByMap(heroMap);
          
    }
    private static List<Hero> findByMap(HashMap<String,List<Hero>> m) {
        long start =System.currentTimeMillis();
        List <Hero>result= m.get("hero-5555");
        long end =System.currentTimeMillis();
        System.out.printf("通过map查找,一共找到%d个英雄,耗时%d 毫秒%n",result.size(),end-start);
        return result;
    }
    private static List<Hero> findByIteration (List<Hero> hs) {
        long start =System.currentTimeMillis();
        List<Hero> result =new ArrayList<>();
        for (Hero h : hs) {
            if(h.name.equals("hero-5555")){
                result.add(h);
            }
        }
        long end =System.currentTimeMillis();
        System.out.printf("通过for查找,一共找到%d个英雄,耗时%d 毫秒%n", result.size(),end-start);
        return result;
    }
    public static int random(){
        return ((int)(Math.random()*9000)+1000);
    }
}

感谢你看到这里,我是程序员麦冬,一个java开发从业者,深耕行业六年了,每天都会分享java相关技术文章或行业资讯

欢迎大家关注和转发文章,后期还有福利赠送!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值