看别人蓝桥杯拿奖,你不馋吗?快来一起学习数据结构吧~

一、Java Collections框架是什么?


Java 集合框架 Java Collection Framework ,又被称为容器 container ,
是定义在 java.util 包下的
一组接口 interfaces 和其实现类 classes 。
其主要表现为将多个元素 element 置于一个单元中,
用于对这些元素进行快速、便捷的
存储 store 、检索 retrieve 、管理 manipulate
即平时我们俗称的增删查改 CRUD

数据尽头谁为峰,一见Collection道成空

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YK75qC55qC55ZGA,size_20,color_FFFFFF,t_70,g_se,x_16


二、Iterable【可迭代的】

如上图:我们常见的Collection接口上面

还实现有一个接口,即:

Iterable【可迭代的】

Interface Iterable<T>:官网文档链接

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YK75qC55qC55ZGA,size_20,color_FFFFFF,t_70,g_se,x_16

  一脉相承:Collection父类接口只有Iterable这一个接口

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YK75qC55qC55ZGA,size_18,color_FFFFFF,t_70,g_se,x_16

但是Iterable接口的继承只是为了让Collection框架中的API都拥有可迭代的功能!


回到Collection接口:

 collection文档官方链接:

8d0b1a17e368be2a48010321628d427f.gif

其中Collection接口下的实现类Classes和Interface太多,需要撰写系列文章。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YK75qC55qC55ZGA,size_20,color_FFFFFF,t_70,g_se,x_16

其中ArrayLisy、Vector 和 LinkedList 类均在Java.util包中,均为可伸缩数组,即可以动态改变长度的数组!~


提到这些品种多花样全的各种数据结构,我们不得不提一句各种数据结构里面种类繁多,令人眼花缭乱的方法!

当我们使用Java提供的数据结构时,比如使用线性数据结构时,我是喜欢先去抽象父类里面去找一找约定的抽象方法,如Collection这个最顶级父类接口

其中顶级的Collection 接口中就规定了抽象方法 toArray() 和 add() 等方法。那么如上图所示:在下面的棕色实现类中都要实现这些方法!

 在非线性的数据结构中,顶级父类 Map接口

Map接口中则未规定Collection中很多地道的方法:比如 toArray() 以及 add()等方法,

Java Collections 框架中包含了大量集合接口以及这些接口的实现类和操作他们的算法(例如排序,查找,反转,替换,赋值,取最小元素,取最大元素等)

这样通过掌握每种数据结构的特性,了解他们的功能和业务使用场景。从而更好的记忆这些数据结构的和常用方法!

通过算法刷题,我总结了如下一部分!

在力扣刷题时我们需要知道在哪儿能用 toArray方法,如Collection 接口下的这些正儿八经的八旗子弟线性数据结构(队列,栈,集合,线性表,链表等)都能用,嘿,就是一个地道!比如说HashSet 虽然人家带Hash 和 HashMap长得很像,但是人家可是正儿八经的实现了顶级父类Collection接口的线性集合!所以HahsSet能使用add尾插增加元素!还能把toArray也给他安排上!很多时候力扣刷题,集合set,HashSet转数组,啪的一下就好了! 咱们的线性数据结构出门儿不走路,嘿,您猜怎么着?全是地道!

Set表示数学意义上的集合概念,其最主要的特点是集合中的元素不能重复,因此存入Set的每个元素都必须定义equals()方法来确保对象的唯一性。

该接口有两个实现类:HashSet 和 TreeSet ~

其中树集 TreeSet 实现了SortedSet接口,因此TreeSet容器中的元素是有序的!


提到add这个增加元素的方法了,补充一句:在此注意 add 虽好,可不要乱用啊,因为他的原理是尾插法的,在屁股后面插入的!

比如当我们使用 栈 的时候,推荐您使用栈的打包三件套 比如 push,pop,peek

分别是,push压栈,pop弹栈,peek查看栈顶元素


 

我们测试发现 顶级父类接口里面Collection 没给栈配套约定这三个方法

一直到了实现类ArrayList 和 LinkedList这两个类内都没有实现 栈和队列 的三件套,方法都是爆红的(不过想想也是,人家根红苗正的线性表 和 链表,跟你栈道和队列的方法沾边儿干嘛? )

想想也不难理解:如果我一开始就在顶级父类接口Collection中约定了 push,pop,peek的三件套,那么下面的任何实现类都要实现这几个方法!但是我线性表和链表根本不需要这三件套啊!

食之无味,弃之也不行,因为Stack栈必要这三个方法不可,那就随用随加!需要的时候再加上。

多层继承,在栈和队列的实现类上再加一层父类接口,约定栈的push,pop,peek和队列的offer,poll,peek这几个方法以及其他所需方法!

Deque接口应运而生!这里的Deque是双端队列的意思,即如:Double ended queue

Deque (Java Platform SE 8 )

Summary of Deque methods
First Element (Head) Last Element (Tail)
Throws exception Special value Throws exception Special value
Insert addFirst(e) offerFirst(e) addLast(e) offerLast(e)
Remove removeFirst() pollFirst() removeLast() pollLast()
Examine getFirst() peekFirst() getLast() peekLast()

This interface extends the Queue interface. When a deque is used as a queue, FIFO (First-In-First-Out) behavior results. Elements are added at the end of the deque and removed from the beginning. The methods inherited from the Queue interface are precisely equivalent to Deque methods as indicated in the following table:

Comparison of Queue and Deque methods
Queue Method Equivalent Deque Method
add(e) addLast(e)
offer(e) offerLast(e)
remove() removeFirst()
poll() pollFirst()
element() getFirst()
peek() peekFirst()

Deques can also be used as LIFO (Last-In-First-Out) stacks. This interface should be used in preference to the legacy Stack class. When a deque is used as a stack, elements are pushed and popped from the beginning of the deque. Stack methods are precisely equivalent to Deque methods as indicated in the table below:

Comparison of Stack and Deque methods
Stack Method Equivalent Deque Method
push(e) addFirst(e)
pop() removeFirst()
peek() peekFirst()

双端队列,双端队列,为甚么叫双端

即在上端能:

  1. 队列出队:poll(),
  2. 栈顶元素弹栈:pop(),
  3. 栈顶元素入栈:push(),
  4. 查看栈顶(队首)元素:peek()

在下端(底层)能够:

  1. 队列入队:offer(),
  2. 祖传方法尾插:add()

面向接口编程,继承的思想,熠熠生辉,永放光芒,一开始写Java数据结构这群人儿小脑瓜真好使!

因为 栈 和 队列其实是不分家的,我们通常需要父类Deque接口!再用继承了Deque的具体实现类LinkedList来声明变量(面向接口编程.doge)。

为什么用LinkedList不用ArrayList,因为ArrayList没实现Deque接口啊,兄弟萌

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

 那么可能就又有朋友要问了,为什么不使用这个Stack实现类呢?人家的名字就叫栈Stack啊! 只能说这个在编写的初期,Vector写的不太好。。。已经被淘汰了(应该是这样说的,逃~doge)

所以我们还是老规矩,左边Deque 右边LinkedList 就能美滋滋的使用 官方提供的栈数据结构啦!

        Deque<String> stack = new LinkedList<>();

        //这里的Deque 是双端队列的意思 即 : DoubleQueue
        stack.push("入栈");
        System.out.println("查看刚才"+stack.peek()+"的元素");
        System.out.println("弹出刚才"+stack.pop()+"的元素");
    

但是,我们回归主题,不忘初心!

当你的数据结构是栈时候 不提倡用add 甚至尽量避免这个继承自顶级父类Collection的方法add

因为我们测试如下代码,发现结果如下



import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

/**
 * @program: leetcode
 * @description:
 * @author: SmallRedSun
 * @create: 2022-04-13 10:35
 **/
public class TestStack {
    public static void main(String[] args) {
        Deque<String> stack = new LinkedList<>();
        stack.push("第一个push入栈");
        stack.push("第二个push入栈");
        stack.push("第三个push入栈");
        stack.push("第四个push入栈");

        while(!stack.isEmpty()){
            System.out.println(stack.pop());
        }

        System.out.println("-----------------隔离线------------");

        Deque<String> stack1 = new LinkedList<>();
        stack1.add("第一个add入栈");
        stack1.add("第二个add入栈");
        stack1.add("第三个add入栈");
        stack1.add("第四个add入栈");

        while(!stack1.isEmpty()){
            System.out.println(stack1.pop());
        }

        System.out.println("-----------------隔离线------------");

        List<String> list = new ArrayList<>();
        list.add("第一个加入线性表");
        list.add("第二个加入线性表");
        list.add("第三个加入线性表");
        list.add("第四个加入线性表");

        for(int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }


    }
}

因为add是尾插,你使用add添加的元素,本来应该在已有元素上面的,现在使用add,变成在已有元素下面!

 如图,使用push是正常的晚来在上,喜封金顶,先进后出 LIFO

但是使用add 就是 直接釜底抽薪 人家是抽,你这是插,一波抽插,顺序正好反了

队列的时候就是正常的先进先出,后进后出,正常三件套 一套带走 offer poll peek ,offer是放入元素,poll是弹出队首元素,peek是查看队首元素。

队列这个数据结构!他就跟我的傻根子一样是个活灵活现骚里骚气的零。你用add插屁股也就插了!罢了!只要注意别在栈里使用add方法,使用的时候也要保持警惕,知道你在干什么!

但是!~~~画风再次一转。作为已经过时的容器 难道Vector 和 它的子类Stack真的过时的一无是处么? 不是的,因为左边是接口Deque,右边是 LinkedList的栈 并没有保证线程安全。而我们在OJ题里面使用栈这种数据结构的时候,牛客实在主类Main中,力扣是在一个方法内!不需要考虑线程的细节。

所以明显使用Deque<E> stack = new LinkedList<>(); 速度更快。


通过上面的分析与学习,我们以一张图开始,从最顶级的Collection接口,延申讲到了List,Queue,Set,Stack这些数据结构。

又围绕着JavaDoc官方的英文文档,去查阅方法,再去Idea里面编写代码测试。

学习数据结构,要变强,最权威的还是要去跟英文文档交手的,这是绕不过去的槛。


总结:

时刻知道你的数据结构是用来存什么数据的:泛型,元素类型

时刻清晰的了解你所选择的数据结构是什么结构:根据结构处置你的数据!

要做到胸有成竹,掌上青轴响,胸中百万兵! 键来!

猜你喜欢

转载自blog.csdn.net/m0_56164356/article/details/123589992