学习大数据的第21天——数据结构、集合(ArrayList、Vector、LinkedList)

归纳常见的数据结构

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

面试的时候,一般会问不用的数据结构都有哪些特点?给你一个场景让你设计不同的数据结构

1、首先先回答涉及的数据结构是什么样子的

2、然后再问答涉及到的数据结构它的有缺点分别是什么,怎么去弥补缺点。

需求:我想把A,B,C三个元素插入到栈数据结构中,怎么做?

image-20220211201845182

存放的顺序:A、B、C

取出的顺序:C、B、A

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

举例现实生活中有哪些栈的实例:

1、子弹夹

2、煤炉烧煤球

队列

需求:我想把A、B、C三个元素放入队列中,怎么做呢?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-muoWEhEN-1644584699752)(C:\Users\stu\AppData\Roaming\Typora\typora-user-images\image-20220211202132069.png)]

存放的顺序:A、B、C

取出的顺序:A、B、C

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

举例现实生活中有哪些队列的案例:

1、排队做核酸

数组

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

静态数组:int [] arr = {11,22,33,44,55};

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SXVTHyNt-1644584699753)(C:\Users\stu\AppData\Roaming\Typora\typora-user-images\image-20220211202510717.png)]

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kjZTypz2-1644584699754)(C:\Users\stu\AppData\Roaming\Typora\typora-user-images\image-20220211202605992.png)]

链表

一个链条有多个节点组成的数据结构

结点:是有两部分组成,是由数据域和指针域组成,包含了数据和指针。需求:将11,22,33,44,55存放到链表中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gBR3KKVi-1644584699754)(C:\Users\stu\AppData\Roaming\Typora\typora-user-images\image-20220211202754166.png)]

链表的特点:查询慢,增删快

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1qLHvj8l-1644584699754)(C:\Users\stu\AppData\Roaming\Typora\typora-user-images\image-20220211202906075.png)]

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CzAKGNfx-1644584699755)(C:\Users\stu\AppData\Roaming\Typora\typora-user-images\image-20220211203711285.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DSwdc5xp-1644584699755)(C:\Users\stu\AppData\Roaming\Typora\typora-user-images\image-20220211203744941.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fx0tZoXc-1644584699755)(C:\Users\stu\AppData\Roaming\Typora\typora-user-images\image-20220211203730924.png)]

二叉树的遍历顺序 :前序遍历,中序遍历,后序遍历,注意:这里的前中后指的是根的顺序

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

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

后序遍历:左右根:44,22,55,66,33,11

工作面试必备
哈弗曼树(最小生成二叉树)

当用 n 个结点(都做叶子结点且都有各自的权值)试图构建一棵树时,如果构建的这棵树的带权路径长度最小,称这棵树为“最优二叉树”,有时也叫“赫夫曼树”或者“哈夫曼树”。

image-20220211205056639

哈夫曼树相关的几个名词

路径:在一棵树中,一个结点到另一个结点之间的通路,称为路径。图 1 中,从根结点到结点 a 之间的通路就是一条路径。

路径长度:在一条路径中,每经过一个结点,路径长度都要加 1 。例如在一棵树中,规定根结点所在层数为1层,那么从根结点到第 i 层结点的路径长度为 i - 1 。图 1 中从根结点到结点 c 的路径长度为 3。

结点的权:给每一个结点赋予一个新的数值,被称为这个结点的权。例如,图 1 中结点 a 的权为 7,结点 b 的权为 5。

结点的带权路径长度:指的是从根结点到该结点之间的路径长度与该结点的权的乘积。例如,图 1 中结点 b 的带权路径长度为 2 * 5 = 10 。

树的带权路径长度为树中所有叶子结点的带权路径长度之和。通常记作 “WPL” 。例如图 1 中所示的这颗树的带权路径长度为:

WPL = 7 * 1 + 5 * 2 + 2 * 3 + 4 * 3

image-20220211204458644
B+树 红黑树 自平衡二叉树

需要掌握红黑树的生成过程,红代表什么,黑代表什么?

有什么特点?

  1. 单一节点存储更多的元素,使得查询的IO次数更少。
  2. 所有查询都要查找到叶子节点,查询性能稳定。
  3. 所有叶子节点形成有序链表,便于范围查询。

大数据中有哪些红黑树的案例?

需要掌握参数的变导致红黑树的变化,怎么去变化的?

红黑树的目的是什么?

将来有哪些优化方式?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-50syFDlY-1644584699756)(C:\Users\stu\AppData\Roaming\Typora\typora-user-images\image-20220211205259577.png)]

哈希表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I9xJWnLJ-1644584699756)(C:\Users\stu\AppData\Roaming\Typora\typora-user-images\image-20220211205333318.png)]

集合ArrayList

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

public class ArrayListDemo1 {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList list = new ArrayList();

        //向集合中添加元素
        list.add("hello");
        list.add("world");
        list.add("java");
        list.add("hadoop");
        list.add("Hive");
        list.add("hello");
        list.add("world");

        System.out.println("去重之前的集合为:" + list);

        //创建新的集合对象
        ArrayList list2 = new ArrayList();

        //创建迭代器
        Iterator iterator = list.iterator();
        //遍历旧的集合
        while(iterator.hasNext()){
            String s = (String) iterator.next();
            //获取到元素之后,拿着这个元素去新集合中查找,如果找到说明重复,就不添加,反之添加到新集合中
            if(!list2.contains(s)){
                list2.add(s);
            }
        }

        System.out.println("去重之后的集合为:" + list2);

    }
}

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

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

我们按照处理字符串重复的逻辑来处理自定义对象重复,发现结果并没有进行去重
为什么呢?
要想知道为什么,就得知道问题出现在了哪一行代码中。
经过简单地分析后发现,问题出现了在判断是否包含的那一行代码中
因为只有当if语句为true的时候,才会将元素添加到新集合中
说明我们这里判断,一直都是为true的,换句话contains这个方法并没有生效
要搞清楚为什么不会生效,就得搞清楚contains这个方法底层是怎么做的。

contains方法底层调用的是equals方法,但是呢,Student类中并没有重写equals方法
所以调用的是Object类中的equals方法,而Object类中的equals方法比较的是地址值,学生对象都是new出来的
地址值必然不一样,equals比较的结果永远是false,加上我们代码中的!,结果永远是为true,所以无论如何都会添加到
新集合中,最终结果没有去重。

解决方法:元素类重写equals()方法 自动生成即可

public class ArrayListDemo2 {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList list1 = new ArrayList();

        //向集合中添加数据
        Student stu1 = new Student("张飞",18);
        Student stu2 = new Student("马超",19);
        Student stu3 = new Student("关羽",20);
        Student stu4 = new Student("刘备",21);
        Student stu5 = new Student("张飞",18);

        list1.add(stu1);
        list1.add(stu2);
        list1.add(stu3);
        list1.add(stu4);
        list1.add(stu5);

        System.out.println(list1);
        //创建新的集合对象
        ArrayList list2 = new ArrayList();

        //迭代器
        Iterator iterator = list1.iterator();
        while(iterator.hasNext()){
            Student student = (Student) iterator.next();
            //注意这里contains里面包含的是equals方法,若Student类中没有重写equals方法的时候,运用的是Object的equals的方法
            //相当于  ==
            if(!list2.contains(student)){
                list2.add(student);
            }
        }

        System.out.println(list2);


    }
}
集合Vector

Vector:
底层数据结构是数组,查询快,增删慢
线程安全,效率低(虽然它是线程安全的,我们今后也不会去使用它,后面会说一个线程安全的类代替它)

Vector特有的方法:
public void addElement(Object obj)
将元素添加到集合的末尾 效果上和add()一样
public Object elementAt(int index)
获取指定索引处的元素 get(int index)
public Enumeration elements()
返回此向量的组件的枚举。

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

        //向集合中添加元素
        //public void addElement(Object obj) 将元素添加到集合的末尾  效果上和add()一样
        vector.addElement("hello");
        vector.addElement("java");
        vector.add("hello");
        vector.add("java");

        System.out.println(vector);

        //public Object elementAt(int index)  获取指定索引处的元素    get(int index)
        System.out.println(vector.elementAt(3));
        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、底层数据结构是双链表,查询慢,增删快
2、线程是不安全的,效率高

LinkedList特有的方法:
1、添加功能:
public void addFirst(Object e) 在集合的开头添加元素
addLast(Object e) 在结合末尾添加元素,等同于add()方法
2、获取功能:
public Object getFirst() 获取集合中的第一个元素
getLast() 获取集合中的最后一个元素
3、删除功能:
public Object removeFirst() 从集合中删除第一个元素并返回
public Object removeLast() 从集合中删除最后一个元素并返回

public class LinkedListDemo1 {
    public static void main(String[] args) {

        //创建LinkedList集合对象
        LinkedList linkedList = new LinkedList();

        //向集合中添加元素
        //public void addFirst(Object e) 在集合的开头添加元素
        //addLast(Object e) 在结合末尾添加元素,等同于add()方法
        linkedList.add("hadoop");
        linkedList.addFirst("hello");
        linkedList.addLast("java");

        System.out.println(linkedList);

        System.out.println("========================");

        //public Object getFirst() 获取集合中的第一个元素
        //getLast()  获取集合中的最后一个元素
        System.out.println(linkedList.getFirst());
        System.out.println(linkedList.getLast());

        System.out.println("========================");
        //public Object removeFirst()  从集合中删除第一个元素并返回
        //public Object removeLast()   从集合中删除最后一个元素并返回
        System.out.println(linkedList.removeFirst());
        System.out.println(linkedList.removeLast());
        System.out.println(linkedList);

    }
}
面试题:

请用LinkedList模拟栈数据结构的集合,并测试
栈的特点:先进后出
题目真正的意思是,自己写一个集合类,底层是LinkedList,调用自己定义的方法实现栈数据结构。

class MyStack{
    private LinkedList linkedList;

    //构造无参的构造方法,初始化LinkedList
    MyStack(){
        linkedList = new LinkedList();
    }
    //自定义的添加方法
    public void MyAdd(Object obj){
        //想要先进后出,所有得将新加入的放在前面
        linkedList.addFirst(obj);
    }

    //自定义的获取元素的方法
    public Object MyGet(){
        //如果使用linkedList.getLast()的话、获取的都是同一个元素
//        return linkedList.getLast();
        return linkedList.removeFirst();
    }

    //判断是否为空
    public boolean myIsEmpty(){
        return linkedList.isEmpty();
    }
}

public class LinkedListTest1 {
    public static void main(String[] args) {
        //创建自定义的集合
        MyStack myStack = new MyStack();

        myStack.MyAdd("hello");
        myStack.MyAdd("java");
        myStack.MyAdd("bigdata");

        while(!myStack.myIsEmpty()){
            Object o = myStack.MyGet();
            System.out.println(o);
        }

//        //创建集合对象
//        LinkedList linkedList = new LinkedList();
//
        linkedList.add("hello");
        linkedList.add("world");
        linkedList.add("java");
//        linkedList.addFirst("hello");
//        linkedList.addFirst("world");
//        linkedList.addFirst("java");
//
//        //遍历
//        Iterator iterator = linkedList.iterator();
//        while (iterator.hasNext()){
//            Object next = iterator.next();
//            System.out.println(next);
//        }
//
//        //如果面试的时候,遇到这样的题目
//        //按照上面的做法,一分都没有

    }
}
泛型

泛型:
把明确数据类型的工作,提前到了编译时期,在创建集合的时候明确存储元素的数据类型。
这样的做法有点向把数据类型当作参数一样传递,所以泛型还有一个叫法:参数化类型

泛型的语句定义格式:
<引用数据类型>
注意:尖括号中的数据类型只能是引用数据类型

泛型的好处:
1、将我们运行时期出现的问题,提前到编译时期
2、不需要做强制类型转换
3、优化了代码。消除了不必要的黄色警告线,使代码看起来更简洁

通过观察API发现,泛型可以出现在类,接口,方法上面,我们看到的类似于这样的都叫泛型,一般来说,泛型出现大多使用的集合中。

public class GenericDemo {
    public static void main(String[] args) {
        //创建一个List集合对象
        //在JDK1.7之后,泛型会进行自动类型推断
        ArrayList<String> list = new ArrayList<>();

        //向集合中添加元素
        list.add("hello");
        list.add("hello");
        list.add("hello");
        list.add("hello");
        list.add("hello");
//        list.add(20);
//        list.add(12.34);
//        list.add(new Student());

        //遍历
//        Iterator iterator = list.iterator();
//        while (iterator.hasNext()) {
//            Object next = iterator.next();
//
//            String s = (String) next; //ClassCastException
//
//            System.out.println(next);
//        }

        //遍历
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            System.out.println(next);
        }

    }
}

/遍历
// Iterator iterator = list.iterator();
// while (iterator.hasNext()) {
// Object next = iterator.next();
//
// String s = (String) next; //ClassCastException
//
// System.out.println(next);
// }

    //遍历
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()){
        String next = iterator.next();
        System.out.println(next);
    }

}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值