Java数据结构-栈和队列

概念:栈是一种特殊的线性表,其只允许在固定的一段进行插入和删除元素操作。进行数据插入和删除的一端称为栈顶,另一端称为栈底。栈中的数据元素遵循后进先出的原则。

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。

出栈:栈的删除操作叫出栈。出数据在栈顶。

栈可以通过数组或链表实现。使用数组实现的栈称为顺序栈,使用链表实现的栈称为链式栈。在实现栈时,需要注意栈的大小,防止栈溢出的问题。

栈的使用

在Java中,可以使用内置的数据结构java.util.Stack来实现栈。

以下是使用Stack类的一些常见操作:

(1)创建栈对象:

Stack<Integer> stack = new Stack<>();

(2)压入元素到栈中:

stack.push(5);
stack.push(10);
stack.push(15);

(3)弹出栈顶元素:

int top = stack.pop(); // 返回并删除栈顶元素

(4)获取栈顶元素但不删除:

int top = stack.peek(); // 返回栈顶元素

(5)判断栈是否为空:

boolean isEmpty = stack.isEmpty();

(6)获取栈的大小:

int size = stack.size();

(7)遍历栈中的元素:

for (Integer element : stack) {
    System.out.println(element);
}

需要注意的是,Stack类是一个遗留的类,推荐使用Deque接口的实现类LinkedList来代替它。使用LinkedList实现的栈可以实现相同的功能,同时还具备其他更多的操作和灵活性。

以下是使用LinkedList来实现栈的示例:

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

stack.push(5);
stack.push(10);
stack.push(15);

int top = stack.pop();
int size = stack.size();

for (Integer element : stack) {
    System.out.println(element);
}

栈的模拟实现

public class MyStack {
    public Object[] elem;
    public int usedSize;

    public MyStack2() {
        this.elem = new Object[10];
    }

    public void push(E val) {
        if(isFull()) {
            //扩容
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        usedSize++;
    }

    public boolean isFull() {
        return usedSize == elem.length;
    }

    public E pop() {
        if(empty()) {
            return null;
        }
        E oldVal = (E)elem[usedSize-1];
        usedSize--;
        return oldVal;
    }

    public E peek() {
        if(empty()) {
            return null;
        }
        //int oldVal = elem[usedSize-1];
        //usedSize--;
        //return oldVal;
        return (E)elem[usedSize-1];
    }

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

栈是一种常见的数据结构,在许多应用场景中都有广泛的应用。

以下是一些常见的栈的应用场景:

  1. 表达式求值:在编程语言中,栈常常用于计算表达式的值。例如,将中缀表达式转换为后缀表达式,并使用栈来计算后缀表达式的值。

  2. 括号匹配:栈可以用于检查表达式中的括号是否匹配。通过遍历表达式中的字符,将左括号压入栈中,当遇到右括号时,弹出栈顶元素并检查是否为对应的左括号。

  3. 函数调用:在函数调用中,栈用于存储函数的局部变量、参数和返回地址。每次调用函数时,将相关信息压入栈中,在函数返回时再弹出。

  4. 浏览器的后退与前进:浏览器的后退和前进功能可以通过栈实现。每次浏览一个页面时,将该页面的 URL 压入栈中,当用户点击后退或前进时,从栈中弹出相应的 URL 进行导航。

  5. 撤销操作:在许多应用程序中,栈用于实现撤销操作。每次用户进行操作时,将相关的操作记录压入栈中,当用户撤销时,从栈中弹出最近的操作并恢复到上一个状态。

  6. 浏览器的历史记录:浏览器的历史记录可以使用栈来实现。每次访问一个页面时,将该页面的 URL 压入栈中,当用户查看历史记录时,依次弹出栈中的 URL 进行展示。

  7. 递归算法:一些算法问题可以通过递归方式解决,而递归中常常使用栈来保存递归的状态。

这些仅是栈的一些应用场景,实际上栈在计算机科学中还有许多其他的应用。栈的特性使其非常适合处理需要"后进先出"(LIFO)的数据操作。

队列

概念:队列是只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出(FIFO)的特性。

入队列:进行插入操作的一端称为队尾。

出队列:进行删除操作的一端称为队头。

队列的使用

在Java中,队列的使用可以通过Java集合框架中提供的Queue接口及其实现类来实现。Queue接口继承自java.util.Collection接口,并提供了一系列用于操作队列的方法。

以下是一些Java队列的常见使用方法:

  1. 创建队列对象:

    Queue<String> queue = new LinkedList<>();
    

  2. 入队操作(添加元素到队尾):

    queue.offer("element"); // 返回true或false,表示添加成功与否
    queue.add("element"); // 添加元素到队尾,添加成功时返回true,否则抛出异常
    

  3. 出队操作(移除并返回队头元素):

    String element = queue.poll(); // 返回队头元素,如果队列为空则返回null
    String element = queue.remove(); // 移除并返回队头元素,如果队列为空则抛出异常
    

  4. 获取队头元素(不移除):

    String element = queue.peek(); // 返回队头元素,如果队列为空则返回null
    String element = queue.element(); // 返回队头元素,如果队列为空则抛出异常
    

  5. 判断队列是否为空:

    boolean isEmpty = queue.isEmpty(); // 返回true或false
    

队列可以根据实际的需求选择不同的实现类,常见的实现类包括LinkedList、ArrayDeque。在选择实现类时,可以考虑队列的使用场景和性能需求。

需要注意的是,Java中的队列接口并没有定义固定容量的限制,所以队列可以按需动态增长。若需要限制队列的容量,可以在使用LinkedList实现队列时,结合队列的大小进行判断和控制。

队列的模拟实现

由于队列是先进先出的特点,所以在模拟队列时,使用链式结构更佳。

public class MyQueue {

    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 void offer(int val) {
        ListNode node = new ListNode(val);
        if(head == null) {
            head = last = node;
        }else {
            last.next = node;
            node.prev = last;
            last = last.next;
        }
    }

    public int poll() {
        if(head == null) {
            return -1;
        }
        int ret = head.val;
        if(head.next == null) {
            head = null;
            last = null;
        }else {
            head = head.next;
            head.prev = null;
        }
        return ret;
    }

    public int peek() {
        if(head == null) {
            return -1;
        }
        return head.val;
    }

    public boolean isEmpty() {
        return head == null;
    }
}

队列在计算机科学和软件开发中有广泛的应用场景,以下是一些常见的应用场景:

  1. 消息队列:用于异步处理系统之间的通信,可以实现解耦和削峰填谷的效果,常见的消息队列包括RabbitMQ、ActiveMQ、Kafka等。

  2. 多线程任务调度:多线程环境下,可以使用队列来实现任务的调度和同步,例如线程池中的任务调度。

  3. 数据缓冲:在数据传输或处理中,队列可以作为缓冲区,临时存储数据,以平衡生产者和消费者之间的速度差异。

  4. 广度优先搜索(BFS):在图的遍历中,使用队列来实现广度优先搜索,即逐层遍历图的节点。

  5. 任务排队系统:用于处理任务的等待和执行顺序,例如批处理系统或作业调度中的任务队列。

  6. 网络请求处理:在服务器端处理网络请求时,可以使用队列来管理请求的顺序,以确保公平处理和资源的合理利用。

  7. 系统调用处理:操作系统内核中的系统调用请求可以使用队列来管理和调度。

需要根据具体的应用场景选择合适的队列数据结构和算法,以满足需求。不同的队列实现方式可能在性能、并发性、持久化等方面有所差异,需根据具体情况进行选择。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值