Day18 常见的数据结构、List的子类ArrayList类、Vector类与LinkedList类

30 篇文章 0 订阅

目录

常见数据结构:

栈:

队列:

数组:

链表:

树:

二叉树:

 二叉树的遍历顺序

哈希表:

图:

图的分类:

图的遍历

 List接口的子类

ArrayList类

Vector类 

Vector类特有的方法

LinkedList类

LinkedList类中的特有方法


常见数据结构:

数据结构:数据的存储格式,以及它的组成格式

栈:

栈的数据结构特点:先进后出

图解:

队列:

队列的数据结构特点:先进先出

图解:

数组:

数组长度是固定的,存储的元素数据类型是一致的,拥有下标索引,方便我们通过索引获取对应位置上的元素值

定义一个数组:int[] arr={11,22,33,44,55}

数组的数据结构特点:查询快,增删慢

图解:

链表:

链表就是有多个结点组成的数据结构

结点:是由两部分组成,是由数据域和指针域组成,包含了数组和指针。

图解:

链表的数据结构特点:查询慢,增删快

树:

树,Tree,它是由根和叶子结点组成的数据结构

叶子结点:当结点下面没有任何分支的时候,我们称该结点为叶子结点

图解:这是一个树:

 当有多个树存在时,我们称这些树总体为森林。

图解:

二叉树:

一个树中每个结点的子结点的个数最多只有两个的时候,这样的树,我们称之为二叉树

图解:

 二叉树的遍历顺序

以上图为例,二叉树的遍历顺序分为三种:前序遍历,中序遍历,后序遍历

注意:这里的前中后指的是根的顺序

前序遍历(根左右,从最顶层的根开始区分左右):  11,22,44,33,55,66

中序遍历(左根右,从最顶层的根开始区分左右):  22,44,11,55,33,66

后序遍历(左右根,从最顶层的根开始区分左右):  44,22,55,66,33,11

其他的一些树:

哈夫曼树:最小生成二叉树

B+树:又称红黑树,自平衡二叉树

哈希表:

哈希表是由哈希函数和Hashtable组成,其中哈希函数可以自定义

图解:

 上述的哈希表的案例中,使用的元素都是数字,但是在实际开发中,数据肯定不止一种数据类型,可能会有其他的数据类型,比如字符串等。这种情况一般都会结合一个哈希函数去存储,可以自己去定义给出哈希函数,也可以不用自己定义,使用源码中给出的哈希函数逻辑,但一般情况下适用,特殊情况下不适用,需要自己修改。

例如将"abc"存放到哈希表中,一般情况下是默认将字符串的每一个字符转换成对应的ASCII码值相加再与哈希表的长度取模求出该字符串存放的位置。

即(97+98+99)%10 = 4,故存放在索引4位置。

虽然解决了存放问题,但若是此时有一个字符串"bac"也要存放进哈希表中,逻辑上来说"bac"字符串应当存放在一个不同的位置上,但是结果是同字符串"abc"存放在同一个索引位置4上。这就形成了一个问题:哈希碰撞

解决办法通常是加上一个随机数,但也只是增大了他们不存放在同一位置上的可能性,因为随机数也有可能两次的随机数相同。

于是在实际开发中,哈希表通常不会单独使用,一般情况下,会与链表结合使用(双链表)

图解:

图:

图是一组由边连接结点的一个图

图解:

图的相关知识:

顶点:图的基本单位,也就是上图中的结点

:指的是顶点之间的关联关系,也就是上图中的线

相邻顶点:由一条边连接在一起的顶点

:指的是一个顶点包含的相邻顶点的数量

权重:边上的数值,也可以理解为两个顶点之间的“距离”

一个图是由G=(V,E)组成,V表示的是一组顶点,E表示的是一组边,用邻接表表示法表示为 :

图的分类:

 图分为有向图和无向图,具体看图解:

图的遍历

 遍历图有两种方式:广度优先搜索(BFS),深度优先搜索(DFS)

无论是哪种搜索方式,搜索出来的答案不绝对,这里给出一个例子:

 上图对图进行遍历:

广度优先搜索:1,2,4,8,3,5,7,6

深度优先搜索:1,2,3,4,8,5,6,7

需求:

给出邻接矩阵,画出对应的图并遍历

图解:

 List接口的子类

ArrayList类

ArrayList类的底层逻辑是数组。具有查询快,增删慢的特点,线程不安全,效率高

ArrayList案例:

需求:使用ArrayList存储字符串并遍历(如果有重复的需要去除)

代码实现:

import java.util.ArrayList;
import java.util.Iterator;

public class ArrayTest1 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("hello");
        arrayList.add("world");
        arrayList.add("java");
        arrayList.add("bigdata");
        arrayList.add("hive");
        arrayList.add("spark");
        arrayList.add("bigdata");
        System.out.println("去重之前的集合:"+arrayList);
//        创建第二个集合对象存放去重之后的集合
        ArrayList list2 = new ArrayList();
//        创建迭代器对象
        Iterator iterator = arrayList.iterator();
//        遍历
        while(iterator.hasNext()){
            String s=(String)iterator.next();
            if(!list2.contains(s)){
                list2.add(s);
            }
//            如果list2中没有该元素,就添加该元素到list2集合中
        }
        System.out.println("去重之后的集合:"+list2);
    }
}

这里集合中bigdata元素重复了一次,需要去除,输出结果:

 需求二:使用ArrayList存储自定义对象并遍历(并去重)

学生对象,姓名和年龄都一样的时候,表示的是同一个人

代码实现:

先创建学生类:

public class Students {
    private String name;
    private int age;

    public Students() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Students{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 再定义ArrayList类进行进一步操作
 

import java.util.ArrayList;
import java.util.Iterator;

public class ArrayTest2 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        Students s1 = new Students("张翼德", 20);
        Students s2 = new Students("赵云", 17);
        Students s3 = new Students("张翼德", 20);
        list.add(s1);
        list.add(s2);
        list.add(s3);
        System.out.println("去重前的集合:");
        System.out.println(list);
        ArrayList list2 = new ArrayList();//定义第二个集合存储去重后的集合
        Iterator iterator = list.iterator();
//        遍历
        while(iterator.hasNext()){
            Students s=(Students)iterator.next();
            if(!list2.contains(s)){
                list2.add(s);
            }
        }
        System.out.println("去重后的集合:");
        System.out.println(list2);
    }
}

输出结果:

 

 根据输出结果来看,虽然实现了遍历,但是并没有实现去重效果,通过分析发现可能是再if判断中出现了问题。

分析:if语句行,只有当if语句为true时,才会执行添加功能,根据输出结果来看,if语句始终是true,也就是说contains方法并没有生效。这是需要进入到contains方法底层实现中去查看

以下为contains的底层实现:

public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

    /**
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))//调用的是equals方法
                    return i;
        }
        return -1;
    }

通过观察底层实现发现contains底层调用的是equals方法,而上述Students类中并没有重写equals方法,因此这里调用的是Object类中的equals方法,故比较的是地址值,学生对象都是new出来的,所以对象地址值必然不一样。故equals结果永远为false,回到if语句中加上!就永远为true,所以无论如何都会添加到新集合中,最终没有实现去重。

解决办法:在元素类Students加入重写equals方法即可,可自动生成。其他代码不变。

 //重写的equals方法
@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Students students = (Students) o;
        return age == students.age && Objects.equals(name, students.name);
    }

此时输出结果即可实现去重:

Vector类 

底层数据结构是数组,查询快,增删慢,线程安全,效率低(虽然安全,但实际开发不使用)

Vector类特有的方法

 public void addElement(Object obj) 将元素添加到集合的末尾 效果上和add()一样

public Object elementAt(int index) 获取指定索引处的元素

get(int index) public Enumeration elements() 返回此向量的组件的枚举。

Vector类举例实现与ArrayList类基本相同,只是方法名不同而已。

代码举例:

import java.util.Enumeration;
import java.util.Vector;
public class VectorDemo {
    public static void main(String[] args) {
        //创建Vector集合对象
        Vector vector = new Vector();

        //向集合添加元素
        vector.addElement("hello");
        vector.addElement("java");
        vector.add("world");
        vector.addElement("java");

//        System.out.println(vector);

//public Object elementAt(int index)获取指定索引处的元素    get(int index)
        Object o = vector.elementAt(0);
        System.out.println(o);
        System.out.println(vector.elementAt(1));
        System.out.println(vector.elementAt(2));
        System.out.println(vector.elementAt(3));
//        System.out.println(vector.elementAt(4));
        System.out.println(vector.get(3));

        System.out.println("=============================================");
        //public Enumeration elements()  返回此向量的元素的枚举。
        //简单记忆 你就把这个对象看作成一个迭代器
        Enumeration elements = vector.elements();
        while (elements.hasMoreElements()) {
            Object o1 = elements.nextElement();
            String s = (String) o1;
            System.out.println(s);
        }


    }
}

LinkedList类

底层数据结构是双链表,查询慢,增删快。线程是不安全的,效率高

LinkedList类中的特有方法

1、添加功能:

public void addFirst(Object e) 在集合的开头添加元素

addLast(Object e) 在结合末尾添加元素,等同于add()方法

2、获取功能:

public Object getFirst() 获取集合中的第一个元素

getLast() 获取集合中的最后一个元素

3、删除功能:

public Object removeFirst() 从集合中删除第一个元素并返回

public Object removeLast() 从集合中删除最后一个元素并返回

 具体功能实现代码举例:

import java.util.LinkedList;

public class LinkedTest1 {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add("hello");
        list.add("world");
        list.add("java");
        System.out.println(list);
//        在集合开头添加元素
        list.addFirst("bigdata");
        System.out.println("开头添加元素:");
        System.out.println(list);
//        在集合末尾添加元素
        list.addLast("superman");
        System.out.println("末尾添加元素:");
        System.out.println(list);
//        获取集合第一个元素
        System.out.println("获取第一个元素:"+list.getFirst());
        System.out.println(list);
//        获取集合最后一个元素
        System.out.println("获取最后一个元素:"+list.getLast());
        System.out.println(list);
//        删除第一个元素
        System.out.println("删除第一个元素"+list.removeFirst());
        System.out.println("删除后的集合:"+list);

//        删除最后一个元素
        System.out.println("删除最后一个元素:"+list.removeLast());
        System.out.println("删除后的集合:"+list);

    }
}

输出结果:

案例: 

 需求:

请使用LinkedList模拟栈数据结构的集合,并测试

分析:题意是需要我们自己设计一个集合类,它的底层逻辑实现是LinkedList类,再调用自己的方法去实现栈数据结构

代码实现:

自己设计的集合类MineStack:

import java.util.LinkedList;

public class MineStack {

    private LinkedList linkedList;
//无参构造,底层为LinkedList无参构造创建对象
    MineStack(){
        LinkedList linkedList = new LinkedList();
    }
//    底层调用linkedList中的添加第一个元素
    void Mineadd(Object obj){
         linkedList.addFirst(obj);
    }
    public boolean ismyEmpty(){
        return linkedList.isEmpty();
    }
//    底层调用为删除第一个元素并返回
    public Object mineGet(){
        return linkedList.removeFirst();
    }
}

由于栈数据结构的特点是先进后出,所以我们需要使用LinkedList类中的removeFirst方法删除第一个元素并返回,这样第二个元素就变成了第一个元素,在下一次遍历时就可以输出该元素,最终实现先进后出,直到集合为空停止

测试类MineStackTest

public class MIneStackTest {
    public static void main(String[] args) {
//        创建对象
        MineStack stack = new MineStack();
//        添加数据到集合
        stack.Mineadd("hello");
        stack.Mineadd("world");
        stack.Mineadd("java");
        stack.Mineadd("bigdata");

//        遍历判断是否含有元素.含有就删除第一个元素并输出该元素
        while(!stack.ismyEmpty()){
            Object o = stack.mineGet();
            System.out.println(o);
        }
    }
}

输出结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值