数据结构基础(二)栈和队列

栈和队列从数据结构的角度来看,也是线性表的一种,但比起线性表,操作少了许多。从数据类型来看,它们是和线性表大不相同的两种重要的抽象数据类型

栈(stack):后进先出(Last In First Out),简称为LIFO线性表。从线性表的特定可知,栈也有顺序栈和链栈两种

  • 顺序栈:采用数组实现,栈的容量有限。也可用代码实现可自增容量的栈。
  • 链栈:采用链表实现,栈的容量没有限度

下面给出顺序栈和链栈的代码。

顺序栈

/**
 * 顺序栈
 */
public class Stack {
    private Object[] elementDates;
    private int top = 0;

    public Stack() {
        this.elementDates = new Object[5];
    }

    public int getSize() {
        if (elementDates == null)
            return 0;
        return elementDates.length;
    }

    public Stack(int capacity) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.elementDates = new Object[capacity];
    }

    /**
     * 返回栈此时的大小
     * @return
     */
    public int getTopPos() {
        return top;
    }

    /**
     * 弹栈
     * @return
     */
    public Object pop() {
        if (top == 0) {
            System.out.println("栈为空,无法弹出");
            return null;
        }
        Object delEle = elementDates[--top];
        return delEle;
    }

    /**
     * 进栈
     * @param o
     */
    public void push(Object o) {
        if (top >= elementDates.length) {
            System.out.println("栈已满,不能继续加入");
            return;
        }
        elementDates[top++] = o;
    }

    /**
     * 返回栈顶部的元素
     * @return
     */
    public Object peek() {
        return top==0?null:elementDates[top-1];
    }
    /**
     * 遍历输出栈中元素
     */
    public void doList() {
        for (int i = 0; i < top; i++) {
            System.out.print(elementDates[i] + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Stack stack = new Stack();
        //测试空栈的弹出特例
        stack.pop();
        //压入几个数据进栈
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(5);
        stack.doList();
        //测试弹栈出栈功能
        stack.pop();
        stack.doList();
        stack.push(6);
        stack.doList();
        //测试满栈压数据的特例
        stack.push(7);
        System.out.println(stack.peek());
        stack.doList();
    }

}/*output:
栈为空,无法弹出
1 2 3 4 5 
1 2 3 4 
1 2 3 4 6 
栈已满,不能继续加入
6
1 2 3 4 6   **/

链栈

import java.util.ArrayList;

/**
 *链栈
 */
public class LinkStack {
    private Node top;
    private int length = 0;

    /**
     * 链表节点
     */
    private static class Node {
        Object item;
        Node pre;

        public Node(Object item, Node pre) {
            this.item = item;
            this.pre = pre;
        }
    }

    public LinkStack() {
        top = null;
    }

    /**
     * 压栈
     * @param o
     */
    public void push(Object o) {
        length++;
        top=new Node(o, top);
    }

    /**
     * 弹栈
     * @return
     */
    public Object pop() {
        if (top == null) {
            System.out.println("栈已为空,无法再弹出");
            return null;
        }
        Node delNode = top;
        //释放引用
        delNode.pre=null;
        top = top.pre;
        length--;
        return delNode.item;
    }

    /**
     * 返回栈顶部的元素
     * @return
     */
    public Object peek() {
        return top==null?null:top.item;
    }
    /**
     * 遍历输出栈中元素
     * 为了顺序输出,先存在arraylist中再反序输出
     */
    public void doList() {
        ArrayList<Object> list=new ArrayList<Object>();
        Node t=top;
        while (t!=null) {
            list.add(t.item);
            t=t.pre;
        }

        for (int i = length-1; i >=0; i--) {
            System.out.print(list.get(i)+" ");
        }
        System.out.println("["+length+"]");
    }

    public static void main(String[] args) {
        LinkStack linkStack = new LinkStack();
        // 测试空栈的弹出特例
        linkStack.pop();
        // 压入几个数据进栈
        linkStack.push(1);
        linkStack.push(2);
        linkStack.push(3);
        linkStack.push(4);
        linkStack.push(5);
        linkStack.doList();
        // 测试弹栈出栈功能
        linkStack.pop();
        linkStack.doList();
        linkStack.push(6);
        System.out.println(linkStack.peek());
        linkStack.doList();
    }
}/*output:
栈已为空,无法再弹出
1 2 3 4 5 [5]
1 2 3 4 [4]
6
1 2 3 4 6 [5]**/

队列

队列(queue):与栈相反,队列是一种先进先出(first in first out,简称FIFO)的线性表。它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。

  • 顺序队列:一片连续的存储空间,设置两个指针进行管理。一个是队头指针front,它指向队头元素;另一个是队尾指针rear,它指向下一个入队元素的存储位置。每次在队尾插入一个元素是,rear增1;每次队头删除一个元素时,front增1。当rear指向分配空间之外时,尽管还有空间,出现溢出错误。
  • 循环队列:为了解决顺序队列浪费空间,对顺序队列的使用方法稍加改进:无论插入或删除,一旦rear指针增1或front指针增1 时超出了所分配的队列空间,就让它指向这片连续空间的起始位置。
  • 链队列:用链表实现的队列,动态创建和删除节点,效率较低,但是可以动态增长。

循环队列:

注意点:

  • 为与rear==front队列为空的情况区分,牺牲一个空间,规定当rear在front的后面时队列已满。
  • 为实现递增长的循环,用(i+1)%length实现

/**
 *循环队列
 */
public class CircleQueue {
    Object[] queue=null;
    private int front=0;
    private int rear=0;

    /**
     * 默认队列数组大小为5
     */
    public CircleQueue() {
        queue=new Object[5];
    }

    /**构造时设置队列数组长度
     * @param capacity
     */
    public CircleQueue(int capacity) {
        if(capacity<=0){
            queue=new Object[5];
            return ;
        }
        queue=new Object[capacity];
    }

    /**
     * 出队
     * @return
     *
     * @author wsz
     */
    public Object deQueue() {
        //当rear==front时判断队列为空
        if(front==rear){
            System.out.println("队列为空,无法弹出");
            return null;
        }

        Object delNode=queue[front];
        front=(front+1)%queue.length;
        return delNode;
    }

    /**
     * 入队
     * @param o
     *
     * @author wsz
     */
    public void enQueue(Object o) {
        //当rear在front后时判断队满
        if((rear+1)%queue.length==front){
            System.out.println("队列已满,无法加入"+o);
            return ;
        }
        queue[rear]=o;
        rear=(rear+1)%queue.length;
    }

    /**
     * 遍历队列
     * @author wsz
     */
    public void doList() {
        for (int i = front; i !=rear ; i=(i+1)%queue.length) {
            System.out.print(queue[i]+" ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        CircleQueue circleQueue=new CircleQueue();
        circleQueue.enQueue(1);
        circleQueue.enQueue(2);
        circleQueue.enQueue(3);
        circleQueue.enQueue(4);
        circleQueue.enQueue(5);
        circleQueue.doList();

        circleQueue.deQueue();
        circleQueue.deQueue();
        circleQueue.deQueue();
        circleQueue.doList();

        circleQueue.enQueue(6);
        circleQueue.enQueue(7);
        circleQueue.doList();

        circleQueue.deQueue();
        circleQueue.deQueue();
        circleQueue.deQueue();
        circleQueue.deQueue();
        circleQueue.doList();
    }
}/*output:
队列已满,无法加入5
1 2 3 4 
4 
4 6 7 
队列为空,无法弹出 **/

链队列

/**
 *链队列
 */
public class LinkQueue {
    /**
     * 队头
     */
    private Node front;

    /**
     * 队尾
     */
    private Node rear;
    /**
     * 队长
     */
    private int length = 0;

    /**
     * 链队节点
     */
    private static class Node {
        Object item;
        Node next;

        public Node(Object item, Node pre) {
            this.item = item;
            this.next = pre;
        }
    }

    public LinkQueue() {
        front = rear=null;
    }

    /**
     * 入队
     * @param o
     */
    public void enQueue(Object o) {
        length++;
        Node node=new Node(o, null);
        //如果此时为空队,把front和rear指向同一个节点
        if(rear==null){
            front=rear=node;
            return ;
        }
        //否则直接加入,修改rear为新加入节点
        rear.next=new Node(o, null);
        rear=rear.next;
    }

    /**
     * 出队
     * @return
     */
    public Object delQueue() {
        //如果队列为空
        if (front == null) {
            System.out.println("队列已为空,无法出队");
            return null;
        }
        Node delNode = front;
        //修改队头为下一个节点
        front = front.next;
        //如果出队后没有节点,把队尾也置为空
        if(front==null)
            rear=front;
        //释放引用
        delNode.next=null;
        length--;
        return delNode.item;
    }


    /**
     * 遍历输出栈中元素
     * 为了顺序输出,先存在arraylist中再反序输出
     */
    public void doList() {
        Node node=front;
        if(node==null)
            return ;
        while (node!=null) {
            System.out.print(node.item+" ");
            node=node.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        LinkQueue linkStack = new LinkQueue();
        // 测试队列的弹出特例
        linkStack.delQueue();
        linkStack.doList();
        // 压入几个数据入队
        linkStack.enQueue(1);
        linkStack.enQueue(2);
        linkStack.enQueue(3);
        linkStack.enQueue(4);
        linkStack.enQueue(5);
        linkStack.doList();
        // 测试出队功能
        linkStack.delQueue();
        linkStack.delQueue();
        linkStack.delQueue();
        linkStack.delQueue();
        linkStack.delQueue();
        linkStack.doList();
        linkStack.enQueue(6);
        linkStack.doList();
    }
}/*output:
栈已为空,无法再弹出
1 2 3 4 5 
6 **/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值