一起学算法(栈篇)

news2024/11/14 16:44:31

1.栈的概念

1.栈的定义

栈是仅限在表尾进行插入和删除的线性表,栈又被称为先进后出的线性表,简称“LIFO”

我们这次用数组作为我们栈的底层数据结构,代码会放到结尾供大家参考使用

2.栈顶的定义

栈是一个线性表,我们允许插入和删除的一端称为栈顶

3.栈底的定义

和栈顶相对的另一端称为栈底,实际上栈底的元素我们不需要关心

4.栈的创建

    //数据容器
    private T[] data;
    //容积
    private int capacity;
    //实际存放的元素个数
    private int size;

2.入栈

1.入栈的定义

栈元素的插入操作叫做入栈,也可以称为进栈、压栈

2.动画演示

 图中是以链表为底层数据结构的,大家看图了解个大概就可以了,具体可以看代码是怎么实现的

3.代码实现

  //在末尾添加元素
    public void addTail(T val) {
        //this.data[size]=val;
        this.add(this.size, val);
    }

    //在中间插入元素
    public void add(int index, T val) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("index is invalid!");
        }
        //判断数组是否满
        if(this.size==this.capacity){
            //数组满的话扩容原来数组的两倍
            int newCapacity=this.capacity*2;
            T[] newDate=(T[]) new Object[newCapacity];//创建一个新的数组
            //进行数组迁移
            for (int i = 0; i < this.size; i++) {
                newDate[i]=this.data[i];
            }
            this.capacity=newCapacity;
            this.data=newDate;
        }

3.出栈

1.出栈的定义

栈元素的删除操作叫做出栈,也可称为弹栈

2.动画演示

 3.代码演示

   //移出末尾
    public T removeTail() {
//        T val=this.data[size-1];
//        this.size-=1;
//        return val;
      return  this.remove(this.size);
    }
   

     //中部移出
    public T remove(int index) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("index is invalid!");
        }
        T val = this.data[index];
        for (int i = index; i < this.size; i++) {
            this.data[i] = this.data[i+1];
        }
        this.size -= 1;

        if(this.size<=this.capacity/4&&this.capacity/2>1){
            int newCapacity=this.capacity/2;
            T[] newDate=(T[])new Object[newCapacity];
            for (int i = 0; i < this.size; i++) {
                newDate[i]=this.data[i];
            }
            this.capacity=newCapacity;
            this.data=newDate;

        }

4.查询栈顶

1.获取栈顶的定义

一般我们可以去查看栈顶的元素是什么

2.动画演示

 3.代码演示

public T peek(T val) {
        return data.getEnByIndex(this.size() - 1);
    }
   

  //获得指定索引的元素
    public T getEnByIndex(int index) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("index is invalid!");
        }
        return this.data[index];
    }

基本的栈能用到的就这些基本的方法,接下来给大家一个完整的代码,供大家学习参考

public class StackDemo<T> implements Stack<T> {
    //以我们封装的数组作为栈的底层数据结构
    private  arrSub<T>data;

    public StackDemo() {
        data=new arrSub<>();
    }

    public StackDemo(int capacity) {
        data=new arrSub<>(capacity);
    }

    @Override//弹栈
    public T pop() {
        return data.removeTail();
    }

    @Override//往栈中添加元素
    public void push(T val) {
        data.addTail(val);
    }

    @Override//查看元素个数
    public int size() {
        return data.getSize();//获得数组元素个数
    }

    @Override//判断是否为空
    public boolean isEmpty() {
        return data.isEmpty();
    }

    @Override//查看栈顶元素
    public T peek(T val) {
        return data.getEnByIndex(this.size() - 1);
    }

    @Override
    public T peek() {
        return null;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("栈顶[");
        T[] arr = data.getData();
        for (int i = size() - 1; i >= 0; i--) {
            sb.append(arr[i]);
            if (i != 0) {
                sb.append(",");
            }
        }
        sb.append("]栈底");
        return sb.toString();
    }


    public static void main(String[] args) {
        Stack<String> stack = new StackDemo<>(10);

        String[] fruits
                = {"apple", "banana", "peach", "watermelon", "strawberry", "pear", "orange", "grape"};

        for (int i = 0; i < fruits.length; i++) {
            stack.push(fruits[i]);
        }
        System.out.println(stack);

        while (!stack.isEmpty()) {
            System.out.println("ele-->" + stack.pop());
            System.out.println(stack + "栈中元素的个数:" + stack.size());
        }
    }
}
public class arrSub<T> {

    //数据容器
    private T[] data;
    //容积
    private int capacity;
    //实际存放的元素个数
    private int size;

    public arrSub(int capacity) {
        this.capacity = capacity;
        this.data = (T[]) new Object[this.capacity];
        this.size = 0;
    }

    public arrSub() {
        this.capacity = 10;
    }

    // 判断数据容器是否为空
    public boolean isEmpty() {
        return this.size == 0;
    }
    public T[] getData(){
       return  this.data;
    }

    //获得数组的容积
    public int getCapacity() {
        return this.capacity;
    }

    //获取元素的个数
    public int getSize() {
        return this.size;
    }

    //首行添加元素
    public void addTop(T val) {
//        for (int i = size-1; i >=0 ; i--) {
//            this.data[i+1]=this.data[i];
//        }
//        this.data[0]=val;
        this.add(0, val);
    }

    //在末尾添加元素
    public void addTail(T val) {
        //this.data[size]=val;
        this.add(this.size, val);
    }

    //在中间插入元素
    public void add(int index, T val) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("index is invalid!");
        }
        //判断数组是否满
        if(this.size==this.capacity){
            //数组满的话扩容原来数组的两倍
            int newCapacity=this.capacity*2;
            T[] newDate=(T[]) new Object[newCapacity];//创建一个新的数组
            //进行数组迁移
            for (int i = 0; i < this.size; i++) {
                newDate[i]=this.data[i];
            }
            this.capacity=newCapacity;
            this.data=newDate;
        }


        for (int i = this.size - 1; i >= index; i--) {
            this.data[i + 1] = this.data[i];
        }
        this.data[index] = val;
        this.size += 1;
    }

    //获得指定索引的元素
    public T getEnByIndex(int index) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("index is invalid!");
        }
        return this.data[index];
    }

    //获得指定元素的索引
    public int getEnByVal(int index, T val) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("index is invalid!");
        }
        for (int i = 0; i < this.size; i++) {
            if (this.data[i] == val) {

                return i;
            }
        }
        return -1;
    }

    //判断是否包含某种布局
    public boolean contains(T val) {
        for (int i = 0; i < this.size; i++) {
            if (this.data[i] == val) {
                return true;
            }
        }
        return false;
    }

    //修改指定索引的元素
    public void upLoad(T var, int index) {
        if (index < 0 || index > this.size) {
            throw new IllegalArgumentException("index is invalid!");
        }
        this.data[index] = var;
    }
    //重写toString的方法

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder(10);
        for (int i = 0; i < this.size; i++) {
            stringBuilder.append(this.data[i] + ",");
        }
        return stringBuilder.substring(0, stringBuilder.lastIndexOf(",") == -1 ? 0 : stringBuilder.lastIndexOf(","));
    }


    //移出末尾
    public T removeTail() {
//        T val=this.data[size-1];
//        this.size-=1;
//        return val;
      return  this.remove(this.size);
    }

    //移出首部
    public T removeTop() {
//        T val=this.data[0];
//        for (int i = 1; i <this.size; i++) {
//            this.data[i-1]=this.data[i];
//        }
//        this.size-=1;
//        return val;
      return  this.remove(0);

    }

    //中部移出
    public T remove(int index) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("index is invalid!");
        }
        T val = this.data[index];
        for (int i = index; i < this.size; i++) {
            this.data[i] = this.data[i+1];
        }
        this.size -= 1;

        if(this.size<=this.capacity/4&&this.capacity/2>1){
            int newCapacity=this.capacity/2;
            T[] newDate=(T[])new Object[newCapacity];
            for (int i = 0; i < this.size; i++) {
                newDate[i]=this.data[i];
            }
            this.capacity=newCapacity;
            this.data=newDate;

        }


        return val;


    }


    public static void main(String[] args) {
        arrSub myArr = new arrSub(50);
        for (int i = 1; i <= 20; i++) {
            myArr.addTail(i + 10);
        }
        System.out.println(myArr);
//        System.out.println("20?" + myArr.contains(20));
//        System.out.println("50?" + myArr.contains(50));
        while (!myArr.isEmpty()) {
            myArr.removeTail();
            System.out.println(myArr);

        }


    }

leetcode题单:

从尾到头打印链表

    public int[] reversePrint(ListNode head) {
        LinkedList<Integer> stack = new LinkedList<Integer>();
        while(head != null) {
            stack.addLast(head.val);
            head = head.next;
        }
        int[] res = new int[stack.size()];
        for(int i = 0; i < res.length; i++)
            res[i] = stack.removeLast();
    return res;
    }

括号的最大嵌套深度

   public int maxDepth(String s) {
      int ans = 0, size = 0;
        for (int i = 0; i < s.length(); ++i) {
            char ch = s.charAt(i);
            if (ch == '(') {
                ++size;
                ans = Math.max(ans, size);
            } else if (ch == ')') {
                --size;
            }
        }
        return ans;
    }

回文链表

public boolean isPalindrome(ListNode head) {
        if(head==null){
            return false;
        }
        StringBuilder s1=new StringBuilder();
        StringBuilder s2=new StringBuilder();
       while(head!=null){
           s1.append(head.val);
           s2.append(head.val);
           head=head.next;
       }
       s2.reverse();
       return s1.toString().equals(s2.toString());}

这里以数组为底层结构的队列代码供大家参考

import java.util.Optional;

public class ArrQueue<T> implements Queue<T> {
    // 队列的容器
    CycleArray<T> data;

    // 构造函数
    public ArrQueue() {
        data = new CycleArray<>();
    }

    public ArrQueue(int capacity) {
        this.data = new CycleArray<>(capacity);
    }

    @Override
    public void offer(T ele) {
        data.addTail(ele);
    }

    @Override
    public T poll() {
        return data.removeHead();
    }

    @Override
    public int size() {
        return data.getSize();
    }

    @Override
    public boolean isEmpty() {
        return data.isEmpty();
    }

    @Override
    public T peek() {
        Optional<T> optional = data.getFront();
        if (optional.isPresent()) {
            return optional.get();
        }
        return null;
    }

    @Override
    public String toString() {
        return data.toString();
    }
}
import java.util.Optional;


/*解决了队列删除时的时间复杂度O(n),循环队列删除时的时间复杂度为O(1)
 * 假设有两个索引,front-->始终指该数组的第一个元素  tail-->始终指向元素插入位置
 * 如果front==tail时,该循环数组为空
 * 如果(tail+1)%capacity=front时,该数组为满状态
 *
 * */
/**
 * 循环队列的底层容器
 */
public class CycleArray<T> {
    // 数据容器
    private T[] data;
    // 容积
    private int capacity;

    // 实际存放元素的个数
    private int size;

    // 声明两个索引  front--队首 tail--队尾
    int front = 0;
    int tail = 0;
    // front === tail  队列是空的  (tail+1)/capacity == front  队列是满的

    public CycleArray() {
        this(10);
    }

    public CycleArray(int capacity) {
        this.capacity = capacity + 1;//因为要浪费一个空间,所以在这里要多加一个空间
        this.data = (T[]) new Object[this.capacity];// 浪费一个空间
        this.size = 0;
    }

    public T[] getData() {
        return this.data;
    }

    // 1、队列是否为空
    public boolean isEmpty() {
        return this.front == this.tail;
    }

    // 2、获取数组的容积
    public int getCapacity() {
        return this.capacity;
    }

    //3、获取实际存放元素的个数
    public int getSize() {
        return this.size;
    }

    // 在队列的尾部添加元素(tail指向待插入元素的位置)
    public void addTail(T val) {
        // 当队列已满,要进行扩容
        if ((this.tail + 1) % this.capacity == this.front) {
            // 新的容积
            int newCapacity = 2 * (this.capacity - 1);
            resize(newCapacity);
        }

        // 将val插入到队列的尾部
        this.data[this.tail] = val;
        // tail向后移动
        this.tail = (this.tail + 1) % capacity;
        // 更新size的值
        this.size += 1;
    }


    private void resize(int newCapacity) {
        T[] newData = (T[]) new Object[newCapacity + 1];
        // 迁移数据 this.front
        int cur = this.front;
        int index = 0;
        while (cur != this.tail) {
            newData[index++] = this.data[cur];
            cur = (cur + 1) % this.capacity;
        }
        // 修改属性
        this.capacity = newCapacity + 1;
        this.data = newData;
        this.front = 0;
        this.tail = this.size;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        int cur = this.front;
        while (cur != this.tail) {
            sb.append(this.data[cur]);
            if ((cur + 1) % this.capacity != this.tail) {
                sb.append(",");
            }
            cur = (cur + 1) % this.capacity;
        }
        sb.append("[" + this.front + "<-->" + this.tail + "]");
        return sb.toString();
    }


    //从队列中移除元素
    public T removeHead() {
        // 1、队列是否为空
        if (this.front == this.tail) {
            return null;
        }
        T val = this.data[this.front];
        this.front = (this.front + 1) % this.capacity;
        this.size--;
        // 缩容
        if (this.size <= this.capacity / 4 && this.capacity / 2 > 1) {
            resize(this.capacity / 2);
        }
        return val;
    }

    public Optional<T> getFront() {
        if (isEmpty()) {
            return Optional.empty();
        }
        return Optional.of(this.data[this.front]);
    }


//     测试
    public static void main(String[] args) {
        CycleArray<Integer> myArr = new CycleArray<>(5);
        for (int i = 1; i <= 15; i++) {
            myArr.addTail(i + 25);
            System.out.println("添加:" + myArr);
            if (i % 3 == 0) {
                int val = myArr.removeHead();
                System.out.println("删除: Header是:" + val);
            }
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/824370.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

I-STARIS国际演艺集团五洲女子组合练习生2023年度考核开启

I-STARIS国际演艺集团五洲女子组合举行了年度考核&#xff0c;从演员的形象管理、表演技巧、才艺水平及中文语言功底等多方面维度来评定。他们非常认真对待&#xff0c;通过不断的努力学习持续提升自己。 作为一年一度的年度考核&#xff0c;大家都非常紧张&#xff0c;除了专业…

tomcat限制IP访问

tomcat可以通过增加配置&#xff0c;来对来源ip进行限制&#xff0c;即只允许某些ip访问或禁止某些来源ip访问。 配置路径&#xff1a;server.xml 文件下 标签下。与同级 <Valve className"org.apache.catalina.valves.RemoteAddrValve" allow"192.168.x.x&…

企业工程管理系统源码-数字化可视化项目管理平台

工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff1a;实现对数据字典标签的增删改查操作 2、编码管理&#xff1a;实现对系统编码的增删改查操作 3、用户管理&#xff1a;管理和查看用户角色 4、菜单管理&#xff1a;实现对系统菜单的增删改查操…

(一)基于Spring Reactor框架响应式异步编程|道法术器

Spring WebFlux 响应式异步编程|道法术器(一) Spring WeFlux响应式编程整合另一种方案|道法术器(二) R2DBC简介 Spring data R2DBC是更大的Spring data 系列的一部分&#xff0c;它使得实现基于R2DBC的存储库变得容易。R2DBC代表反应式关系数据库连接&#xff0c;这是一种使用…

网络四元组

问题描述与解释 四元组&#xff0c;简单理解就是在 TCP 协议中&#xff0c;去确定一个客户端连接的组成要素&#xff0c;它包括 1、源 IP 地址 2、目标 IP 地址 3、源端口号 4、目标端口号 正常情况下&#xff0c;我们对于网络通信的认识可能是这样&#xff08;如图&#xff09…

【力扣每日一题】2023.8.2 翻转卡片游戏

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 这道题不是什么翻转卡片游戏&#xff0c;这就是纯纯的文字游戏&#xff0c;要是能看懂题目那就是非常简单&#xff0c;接下来我就给大家分…

相机存储卡数据恢复,掌握这2个方法就够啦!

“上次和朋友出去旅游拍了好多好看的视频和照片&#xff0c;都特别有纪念意义。但将相机存储卡插入电脑后&#xff0c;很多照片和视频都消失了&#xff0c;怎么恢复相机存储卡里照片呢&#xff1f;求帮助&#xff01;” 对于喜欢拍摄的朋友来说&#xff0c;相机的存储卡真的是个…

elb 直接配置到后端服务器组

出现上图报错的原因是&#xff0c;前面elb配置了https证书&#xff0c;后端的nginx也配置了证书&#xff0c;导致冲突。 需要修改后端的nginx配置文件&#xff0c;将证书配置注释掉。 如果出现健康检查异常&#xff0c;需要在对应服务器的安全组上配置elb所在的网段的访问权限…

不同USB口上的颜色各有什么含义和区别?

在生活中&#xff0c;当我们仔细观察手机、电视、电脑、音箱等电子设备时&#xff0c;就会发现USB端口的颜色有很多。单纯的你可能会认为只是为了好看&#xff0c;实际上不同的颜色代表着不同性能。 01.USB接口的概念 USB通用串行总线&#xff08;Universal Serial Bus&#x…

JVM内存模型【入门】

计算机结构简图 JVM内存模型 详细说明&#xff1a;https://blog.csdn.net/m0_71777195/article/details/126247090 什么是JVM&#xff1f; JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;JVM是一个虚构出来的计算机&#xff0c;有着自己完善…

VMware vSphere整体解决方案及实验拓扑

VMware vSphere整体解决方案及实验拓扑 VMware vSphere完整的解决方案 VMware vSphere有两个核心组件&#xff1a;ESXI&#xff0c;vCenter。ESXI实现的是单机虚拟化&#xff0c;而vCenter实现集群虚拟化&#xff0c;把所有的ESXI统一进行管理。当然了&#xff0c;要想是实现…

IntelliJ IDEA 2023.2新特性详解第二弹!

4 性能分析器 4.1 从 Run&#xff08;运行&#xff09;工具窗口使用分析功能 2023.2 中&#xff0c;可直接从 Run&#xff08;运行&#xff09;工具窗口轻松访问 IntelliJ 分析器的功能。 使用新按钮&#xff0c;点击即可调用&#xff1a; Attach IntelliJ Profiler&#xff…

基于“RWEQ+”集成技术在土壤风蚀模拟与风蚀模数估算、变化归因分析中的应用

土壤风蚀是一个全球性的环境问题。中国是世界上受土壤风蚀危害最严重的国家之一&#xff0c;土壤风蚀是中国干旱、半干旱及部分湿润地区土地荒漠化的首要过程。中国风蚀荒漠化面积达160.74104km2&#xff0c;占国土总面积的16.7%&#xff0c;严重影响这些地区的资源开发和社会经…

Linux【网络基础】之宏观认识

文章目录 一、计算机网络背景二、计算机网络协议&#xff08;1&#xff09;网络协议的概念&#xff08;2&#xff09;协议分层&#xff08;3&#xff09;数据封装与分用&#xff08;4&#xff09;地址管理 一、计算机网络背景 学习计算机网络我们首先要有宏观的认识&#xff0…

03|Oracle学习(主键约束、联合主键)

1. 主键约束介绍 主键&#xff1a;数据表中的一个或多个字段&#xff0c;用于唯一标识数据表中的一条记录。 2. 添加主键约束 2.1 在创建表时添加约束 写法1&#xff1a; CREATE TABLE tb_students(stu_num char(5) primary key,stu_name varchar(10) not null,stu_sex cha…

在政策+市场双轮驱动下,深眸科技助力机器视觉行业走向成熟

近年来&#xff0c;随着人工智能发展的不断提速&#xff0c;机器视觉作为其重要的前沿分支&#xff0c;凭借着机器代替人眼来做测量和判断的能力&#xff0c;广泛应用于工业领域的制造生产环节&#xff0c;用来保证产品质量、控制生产流程、感知环境等&#xff0c;并迸发出强劲…

滴滴数据服务体系建设实践

什么是数据服务化 大数据开发的主要流程分为数据集成、数据开发、数据生产和数据回流四个阶段。数据集成打通了业务系统数据进入大数据环境的通道&#xff0c;通常包含周期性导入离线表、实时采集并清洗导入离线表和实时写入对应数据源三种方式&#xff0c;当前滴滴内部同步中心…

sql入门基础-2

Dml语句 对数据的增删改查 关键字 Insert增 Update删 Delete改 添加数据 给指定字段添加数据 Insert into 表明 (字段名1&#xff0c;字段名2) values&#xff08;值1&#xff0c;值2&#xff09;; 给全部字段添加数据--(根据位置对应添加到字段下) Insert into 表名 values…

24考研数据结构-树与二叉树的基本概念

目录 第五章&#xff1a;树5.1树的基本概念5.1.1树的定义5.1.2 基本术语5.1.3 树的性质 5.2二叉树的概念5.2.1 二叉树的定义与特性5.2.2 几种特殊的二叉树5.2.3 二叉树的性质5.2.4 完全二叉树的性质5.2.5 二叉树的存储结构1. 顺序存储重要的基本操作非完全二叉树2. 链式存储逆向…

Flowable-子流程-事件子流程

目录 定义图形标记XML内容使用示例视频教程 定义 事件子流程是 BPMN 2.0 中加入的新元素&#xff0c;它是指通过事件触发的子流程&#xff0c;可以存在于在流程 级别&#xff0c;或者任何子流程级别。和内嵌子流程类似&#xff0c;把一系列的活动归结到一起处理&#xff0c;不…