当前位置: 首页 > news >正文

购买主机可以做网站吗免费智能seo收录工具

购买主机可以做网站吗,免费智能seo收录工具,玉溪网站设计,网站上的淘客组件是怎样做的栈的概念 栈是一种先进后出的线性表,只允许在固定的一端进行插入和删除操作。 进行插入和删除操作的一端被称为栈顶,另一端被称为栈底 栈的插入操作叫做进栈/压栈/入栈 栈的删除操作叫做出栈 现实生活中栈的例子: 栈的模拟实现 下面是Jav…

栈的概念

栈是一种先进后出的线性表,只允许在固定的一端进行插入和删除操作。
进行插入和删除操作的一端被称为栈顶,另一端被称为栈底

栈的插入操作叫做进栈/压栈/入栈
栈的删除操作叫做出栈

在这里插入图片描述
现实生活中栈的例子:
在这里插入图片描述

栈的模拟实现

下面是Java集合类给我们提供的栈的方法:

在这里插入图片描述

模拟实现顺序栈

我们通过数组来模拟实现栈。

构建数组栈

我们需要两个成员变量,一个是数组,另一个是记录当前的数据个数。

    public int[] elem;public int usedSize;public MyStack() {elem = new int[5];}

push

要考虑扩容问题

    private boolean isFull() {if(usedSize == elem.length) {return true;}return false;}private void grow() {elem = Arrays.copyOf(elem,2*elem.length);}public void push(int val) {if(isFull()) {grow();}elem[usedSize++] = val;}

isEmpty

判断栈是否为空:

    public boolean isEmpty() {return usedSize == 0;}

pop

设置自定义异常:

public class PopException extends RuntimeException{public PopException() {super();}public PopException(String message) {super(message);}
}

删除栈顶的同时,还会返回删除的元素

    private void checkPop() throws PopException{if(isEmpty()) {//抛异常throw new PopException("栈已空,无法删除!!!");}}public int pop() {try {checkPop();int ret = elem[usedSize-1];usedSize--;return ret;} catch (PopException e) {e.printStackTrace();}return -1;}

peek

获取栈顶元素 但是不删除

    public int peek() {try {checkPop();return elem[usedSize-1];} catch (PopException e) {e.printStackTrace();}return -1;}

链式栈

链式栈顾名思义就是利用链表来保存栈

假设使用单链表制作链式栈,建议使用头插和头删法来进行push和pop操作,peak直接把头节点的值获取即可,这样时间复杂度可以为O(1);但是如果你使用尾插和尾删就是以尾节点的位置作为栈顶,在push,pop 和 peak 的时候,时间复杂度为O(N)

假设使用双向无头循环链表,无论是选择头插头删还是尾插尾删作为push与pop,时间复杂度都是O(1)

这里就不演示链式栈的代码。

Stack 的使用

在这里插入图片描述
push 入栈;pop 出栈;peak 获取栈顶元素;empty 是否为空;size 这个获取有效元素的方法是在Vector 中的,search 找到某元素距离栈顶元素的距离多少(栈顶元素记为1,然后一直到目标元素)

栈、虚拟机栈、栈帧有什么区别呢?

栈是我们的数据结构的其中一种形式,虚拟机栈是JVM虚拟机的一块内存,栈帧是运行一个方法或者函数的时候计算机给它开辟的内存。

队列的概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)

队列类似我们生活中的排队。

在这里插入图片描述

队列的模拟实现

在这里插入图片描述
上面是Java集合类给我们提供的队列的方法,其中add和offer都是入队操作,poll 和 remove 都是出队操作,element 和 peek 都是获取队列头部的元素。

它们主要的区别是会不会抛异常~~ 下面有详细的介绍:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


链式队列

这里我们将使用数组来模拟实现队列,并且这里只实现下图所示的方法:
在这里插入图片描述

size 和 isEmpty 是队列继承的方法,并且队列没有重写这两个方法,所以上面的IDEA直接看队列的Structure 是看不到的。


假设我们使用单链表为基础,该怎么实现队列?
假设入队采用尾插,那要出队即使用头删即可
出队列使用单链表的头删即可,时间复杂度为O(1)
入队列使用尾插,一般情况下,单链表实现尾插首先要找到尾,然后才是开始插入,这时候时间复杂度就尾O(N),不是最优解,我们可以加一个尾指针保存好尾节点,这样就方便我们快速进行尾插操作。

假设入队使用头插,那出队的时候就需要使用尾删
这时候就不好弄了,即使你有尾指针在进行尾删的时候还是需要遍历链表找到尾节点的前一个结点才能完成尾删,这时候你可能会认为再定义一个指针,这就很麻烦了。

所以单链表构建队列的话,限制条件有点大,但是使用上一片文章的双向链表(无头双向循环链表 LinkedList) ,就可以随意选取一端作为入队,另一端作为出队。

这里我们入队采用尾插,出队采用头删:

public class MyQueue {public static class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;public ListNode last;//入队public boolean offer(int data) {ListNode node = new ListNode(data);if(isEmpty()) {last = head = node;} else {last.next = node;node.prev = last;last = node;}return true;}public boolean isEmpty() {return head == null;}//出队public int poll() {if(isEmpty()) {return -1;}int ret = head.val;if(head.next != null) {head.next.prev = null;}head = head.next;return ret;}//求结点个数public int size() {ListNode cur = head;int count = 0;while(cur != null) {count++;cur = cur.next;}return count;}//获取队头元素public int peek() {if(isEmpty()) {return -1;}return head.val;}
}

这里要注意出队的代码,如果只有一个结点的情况下,你进行删除后就没有结点了,head.next.prev = null 这行代码就会发生报错。

顺序队列

顺序队列我们采用数组来实现队列,这时候我们就要思考一个问题,在不断的出队入队的情况下怎么保证空间尽可能地利用起来?
假设数组的数据已满装满的情况下,我们一直出队直到数组变空的话,怎么利用起来前面的空间?

在这里插入图片描述

循环队列

这时候我们就需要使用循环队列让队列的空间有效的利用起来。

法1 :定义一个成员变量,usedSize 记录使用了多少的空间
法2 : 定义一个标记符,记录空间是否已满
法3 :浪费一个空间,通过数学公式判断队列是否已满

在这里插入图片描述
一般情况下,我们会认为这就是队列空和满的两种状态,但是这两种状态都是 front == near,怎么办?
根据法1,我们可以记录使用了多少空间的usedSize 来判断队列是否已满,即 usedSize = 数组的长度即可认为队列已满
根据法2,我们使用标记符,首先 将标记符记为 -1,认为队列没满,当front 与near 再次相遇时,标记符乘 -1 变为1 ,判断 队列 已满,如果下一个操作时出队,那标记符再自乘 -1变回 -1 ,当front 与 rear 再次相遇时标记符自乘 -1 变为1 表示队列已满,以此类推,这里大家可以自由发挥。


第三个方法是利用队列自身来进行判断,当 rear 的下一个就是 front 的时候(即 ( rear + 1 ) % 数组长度 == front),就判断队列已满,这需要我们浪费队列的一个空间。
在这里插入图片描述


如何让rear 和 front 循环起来呢?即rear 的下标该如何制定呢?
这里有一个公式,当 rear 要 自增的时候,新的 rear = ( rear + 1 ) % 数组长度就是此时rear 对应的实际下标,当 rear 为 7 时,rear 向下移动一格时,新的 rear 就是 ( 7 + 1 ) % 8 = 0, 正好就是 7 下一个的下标值 0


问题拓展 (数组下标循环的小技巧)

下标往后移动(offset 小于 array.length): index = (index + offset) % array.length

在这里插入图片描述


下标往前移动(offset 小于 array.length): index = (index + array.length - offset) % array.length

array.length - offset 其实就是变相地让 小标变成向后 移动。
在这里插入图片描述


顺序队列的代码
public class MyQueue {int front;int rear;int[] elem;public MyQueue() {elem = new int[4];}//入队public boolean offer(int data) {if(isFull()) {return false;}elem[rear] = data;rear = (rear + 1) % elem.length;return true;}//队列是否已满private boolean isFull() {return (rear + 1) % elem.length == front;}//队列是否为空public boolean isEmpty() {return rear == front;}//出队public int poll() {if(isEmpty()) {return -1;}int ret = elem[front];front = (front + 1) % elem.length;return ret;}//求元素个数public int size() {int count = 0;for (int i = front; i < rear; i++) {count++;}return count;}//获取队头元素public int peek() {if(isEmpty()) {return -1;}return elem[front];}
}

Queue

在这里插入图片描述
上面是我们常用的队列方法

在这里插入图片描述
队列Queue本质上是一个接口,所以Queue 不能被实例化,那如何使用?

Deque (双端队列)

双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。
那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。

在这里插入图片描述
在这里插入图片描述
我们可以发现 Deque 其实是继承了 Queue 接口,但是还是一个接口,还是不能实例化,那怎么使用?请看下面解说。

LinkedList 和栈与队列的关系

在这里插入图片描述

在这里插入图片描述

LinkedList 有很多接口其中包括了 Deque ,而Deque 这个接口其实继承了 Queue ,也就是队列,所以我们可以实例化 一个LinkedList 对象然后通过 Queue 接收就可以使用普通队列的方法,同理,通过实例化一个LinkedList 对象然后通过 Deque 接收就可以使用双端队列的方法


    public static void main(String[] args) {LinkedList<Integer> linkedList = new LinkedList<>();linkedList.push(1);linkedList.push(2);linkedList.push(3);System.out.println(linkedList.peek());System.out.println(linkedList.pop());System.out.println(linkedList.peek());}

在这里插入图片描述

LinkedList还可以当成栈来使用,也就是说LinkedList还包含栈的方法,自身功能很强大。

小结:
LinkedList 不仅可以作为不带头的双向循环链表使用,还可以当成栈或者队列使用。


在实际工程中,使用Deque接口是比较多的,栈和队列均可以使用该接口。

Deque<Integer> stack = new ArrayDeque<>();//双端队列的线性实现
Deque<Integer> queue = new LinkedList<>();//双端队列的链式实现

习题链接:
http://t.csdnimg.cn/aV91m

http://www.hkea.cn/news/3230/

相关文章:

  • 免费公安网站模板郑州网站制作推广公司
  • 做网站需要的图片大小怎样在百度上免费做广告
  • wordpress图片多选百度seo怎么样优化
  • 邮箱官网登录入口seo自然排名关键词来源的优缺点
  • 网站怎么做才可以做评价阿里指数在哪里看
  • seo学习网站网络推广优化网站
  • 京东商城网站建设目标360搜索引擎推广
  • 让人做网站需要注意什如何创建自己的个人网站
  • python做电子商务网站北京seo招聘
  • 深圳网站建设q479185700強百度小说排行榜
  • 网站首页大图的尺寸济南网站建设老威
  • 拨付网站建设费用的报告广州网络公司
  • 代做课件的网站如何建立自己的网站?
  • 网站怎么做评估广告公司联系方式
  • 网站建设服务标准化四种营销模式
  • 秦皇岛网站建设报价sem是什么设备
  • 图片展示网站织梦源码seo推广软件排行榜
  • 专门做儿童的店铺网站百度竞价托管代运营公司
  • 服装网站设计公司网站建设高端公司
  • 江苏高校品牌专业建设网站网站推广论坛
  • 网站域名记录值公司排名seo
  • 手表网站有哪个比较好徐州seo推广优化
  • 怎么做招聘网站百度安装下载
  • wordpress页面湖北seo诊断
  • 上海建设单位工程备案网站网络营销的工具和方法有哪些
  • 如何让网站互动起来廊坊网站建设优化
  • 公司官网包括什么内容网站怎么seo关键词排名优化推广
  • 咨询公司名字大全优化绿松石什么意思
  • 做相片软件网站搜索引擎优化排名技巧
  • wordpress加关键字seo营销方法