还债系列之数据结构——栈和队列

三、栈

还记得当初第一次学习编程的时候还是8051单片机中的汇编语言,现在还记得很清楚,当初遇到的一个简单的数据结构就是——栈,对应的汇编语言中的命令是pushpop。这个结构在生活中是有很多类似的例子的,比如水杯、碗等。该结构的特点如下:

  • 最大特点是先进后出、后进先出
  • 使用一个指针标识栈中元素的位置——栈顶,该值指的是在栈中最上面元素的位置;

针对栈的基本操作主要有:

  • 入栈
  • 出栈
  • 是否为空

具体的实现类如下:

public class Stack<T> {
    private int top = 0;
    private Object[] items;

    public Stack(){
        items = new Object[10];
    }

    public Stack(int initSize){
        items = new Object[initSize];
    }

    public synchronized T push(T item){
        if(top > items.length){
            throw new IllegalStateException("elements appear in this stack are full");
        }
        items[top++] = item;
        return item;
    }

    public synchronized T pop(){
        if(top <= 0){
            throw new IllegalStateException("no element appear in this stack");
        }
        T item = (T)items[top-1];
        items[top-1] = null;
        top--;
        return item;
    }

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

    public int size(){
        return top;
    }
}

测试类如下:

com.demo.category.Stack<String> stack = new com.demo.category.Stack<>();
stack.push("test1");
stack.push("test2");
stack.push("test3");
stack.push("test4");
stack.push("test5");
System.out.println("count: " + stack.size());

String src1 = stack.pop();
String src2 = stack.pop();
String src3 = stack.pop();
System.out.println("count: " + stack.size());
System.out.println("src1: " + src1);
System.out.println("src2: " + src2);
System.out.println("src3: " + src3);

在针对栈的操作中要注意以下问题:

  • 会有数量的限制,导致越界;如果想要使用的栈是无限容量的,就要随时保证数组的容量比实际的元素要多,因此会涉及到数组的扩容问题,当然如果你不是通过数组来实现栈的,也可以使用链表来实现,这样就不必要考虑容量的问题;
  • 多线程环境下操作的互斥;

四、队列

队列这种数据结构在生活中也是有各种各样的类似的例子,比如隧道里,先进入的车肯定是先出来的,这种特点和栈正好是相反的:

  • 先进先出(FIFO),后进后出;

所以在队列中所有的元素都是有序的,一切行为的产生都是按照顺序来的,但是也有例外,比如为了区分优先级而设计出来的优先队列。而在队列中又可以细分成单向队列和双向队列。

4.1 单向队列

在单向队列中是队列中最简单的一种,它的特点如下:

  • 入队:只能从队尾添加元素,也就说不能插队;
  • 出队:只能从队头删除元素,也就说只有轮到你的时候才能离开,否则就老老实实待着;

单向队列如下:

public class Queue<T> {
    private Object[] items;
    private int tail = 0;
    private int head = 0;
    private int size;

    public Queue(int initSize){
        items = new Object[initSize];
    }

    public boolean add(T item){
        if(size == items.length){
            throw new IllegalStateException("no space for the new element");
        }
        items[tail] = item;
        tail++;
        size++;
        return true;
    }

    public T remove(){
        if(size == 0){
            throw new IllegalStateException("no element in this queue");
        }
        T item = (T)items[head];
        items[head] = null;
        head++;
        size--;
        return item;
    }

    public int size(){
        return size;
    }
}

在上述的例子中,队列是通过数组来实现的,示意图如下:

这里写图片描述

4.2 双向队列

双向队列则对于元素的出队和入队限制很松:

  • 入队:即可以在队头,也可以在队尾;
  • 出队:队头可以出队,队尾也可以出队;

该双向队列可以直接继承自单向队列,代码如下:

public class Biqueue<T> extends Queue<T> {
    public Biqueue() {
        super.items = new Object[10];
    }

    public Biqueue(int initSize) {
        super.items = new Object[initSize];
    }

    public boolean addTail(T item) {
        return super.add(item);
    }

    public T removeHead() {
        return super.remove();
    }

    // 队头入队
    public boolean addHead(T item) {
        if (size == items.length) {
            throw new IllegalStateException("no space for the new element");
        }
        if (head == 0) {
            if (size > 0) {
                // 插队是要付出代价的,即所有后面的元素都要跟着变化
                for (int i = size - 1; i >= 0; i--) {
                    items[i + 1] = items[i];
                }
            }
            items[head] = item;
            tail++;
        } else if (head > 0) {
            items[head - 1] = item;
            head--;
        }
        size++;
        return true;
    }

    // 队尾出队
    public T removeTail() {
        if (size == 0) {
            throw new IllegalStateException("no element in this queue");
        }
        T item = (T) items[tail - 1];
        items[tail - 1] = null;
        tail--;
        size--;
        return item;
    }
}

上述所有的操作均没有考虑多线程的环境,如果要在多线程的环境下操作需要考虑互斥。

针对数据结构的操作,之前一直以为知道数据结构的特性即可,感觉实现起来应该不难,但是真正地去实现一个的时候,才知道要考虑的问题很多!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值