java版数据结构之栈和队列

栈是仅在表尾进行插入或删除操作的线性表,又称 后进先出 的线性表

  • 栈接口设计
    interface Stack <T>{
    
        void destroyStack();
        boolean isEmpty();
        int stackLength();
        T getTop(); //取栈顶元素
        void Push(T element); //进栈操作
        T Pop(); //出栈操作
        void stackTraverse();
    }
    

顺序栈

以顺序表基础的栈实现

  • 实现代码
    public class SqStack<T> implements Stack<T> {
    
        private final int MAX_SIZE = 10; //栈的最大容量
        private Object[] array;  //基于数组的顺序栈
        private int length; //栈内元素个数
        
        private int top; //栈顶标识
        private int base;//栈底标识
        
        public SqStack() {  //初始化栈
            
            array = new Object[MAX_SIZE]; //初始化栈的最大容量
            length = 0;
            top = 0;
            base = 0;
        }
        
        @Override
        public void destroyStack() {
            // TODO Auto-generated method stub
            top = 0;
            length = 0;
        }
    
        @Override
        public boolean isEmpty() {
            // TODO Auto-generated method stub
            if(this.length == 0)
                return true;
            else
                return false;
        }
    
        @Override
        public int stackLength() {
            // TODO Auto-generated method stub
            return length;
        }
    
        @Override
        public T getTop() { //去栈顶元素
            // TODO Auto-generated method stub
            return (T)array[top - 1];  //返回栈顶元素
        }
    
        @Override
        public void Push(T element) { //进栈操作
            // TODO Auto-generated method stub
            array[top++] = element;
            length++;
        }
    
        @Override
        public T Pop() {//出栈操作
            // TODO Auto-generated method stub
            length--;
            return (T) array[--top];  //返回栈顶元素,top减一
            
        }
    
        @Override
        public void stackTraverse() { //从栈底依次向栈顶遍历
            // TODO Auto-generated method stub
            for(int i = base; i< top; i++) {
                System.out.print(array[i] + " ");
            }
            System.out.println();
        }
    }
    
  • 代码解析
    • 顺序栈的长度就是top标识的索引值,length属性可有可无。
    • 出栈操作先返回栈顶元素,再top–而代码中为 return (T) array[--top]; 因为数组中的元素为 array[0]~array[top-1]

链式栈

以链表为基础的栈实现

  • 代码实现
    class LinkStack<T> implements Stack<T> {
    
        private class Node{  //节点类
            
            private Node next; //后继引用
            private T dataElement;
            
            public Node() {   //构造头节点
                // TODO Auto-generated constructor stub
                this.next = null;   //节点中的next(连接下一个节点)
                this.dataElement = null;
            }
            public Node(T dataElement) {  //构造尾节点
                // TODO Auto-generated constructor stub
                this.next = null;
                this.dataElement = dataElement;
            }
        }
        
        private Node top;//栈顶结点
        private Node base;//栈底结点(这里栈底结点就是头节点)
        private int length;
        
        public LinkStack() {
            // TODO Auto-generated constructor stub
            base = new Node(); //初始化栈底结点
            top = base;
            length = 0;
        }
        
        @Override
        public void destroyStack() { //重置栈
            // TODO Auto-generated method stub
            top = base;
            length = 0;
        }
    
        @Override
        public boolean isEmpty() {
            // TODO Auto-generated method stub
            if(this.length == 0)
                return true;
            else
                return false;
        }
    
        @Override
        public int stackLength() {
            // TODO Auto-generated method stub
            return length;
        }
    
        @Override
        public T getTop() {
            // TODO Auto-generated method stub
            return top.dataElement;
        }
    
        @Override
        public void Push(T element) { //进栈操作
            // TODO Auto-generated method stub
            //链栈所构造的链表是一个倒过来的常规单向链表
            Node newNode = new Node(element);  
            newNode.next = top;
            top = newNode;
            length++;
        }
    
        @Override
        public T Pop() { //出栈操作
            // TODO Auto-generated method stub
            T data = top.dataElement;
            top = top.next;
            length--;
            return data;
        }
    
        @Override
        public void stackTraverse() { //遍历
            // TODO Auto-generated method stub
            Node currentNode = top;
            while(currentNode.next != null) {
                System.out.print( currentNode.dataElement + " ");
                currentNode = currentNode.next;
            }
            System.out.println();
        }
    }
    
  • 代码解析
    • 栈的push操作

      栈的进栈操作将新结点新结点的后继引用指向top结点,而base结点为最底层的头节点,所以链栈实际上的一个倒过来的常规单向链表,最上层为新进结点。

    • 栈的出栈操作

      将top结点返回,并将top重置为top的后继结点

队列

队列是一种先进先出的线性表

  • 队列接口设计
    interface Queue<T> {
    
        void destroy();//重置队列
        boolean isEmpty();
        int queueLength();
        T getHead();//去对头元素
        void enQueue(T element); //进队列
        T deQueue();//出队列
        void queueTraverse(); //队列的遍历
    }
    

顺序队列

以顺序表为基础实现的队列

  • 代码实现
    class SqQueue<T> implements Queue<T> { 
    
        private final int MAX_SIZE = 10; //队列的最大容量
        private Object[] array; //数组容器
        private int front;//队头
        private int rear;//对尾
        
        public SqQueue() { //初始化队列
            // TODO Auto-generated constructor stub
            array = new Object[MAX_SIZE];
            front = rear = 0;
        }
        @Override
        public void destroy() { //重置队列
            // TODO Auto-generated method stub
            rear = front; //当队尾等于对头时,队列就为空队列
        }
    
        @Override
        public boolean isEmpty() {
            // TODO Auto-generated method stub
            if(front == rear)
                return true;
            else 
                return false;
        }
    
        @Override
        public int queueLength() {//取队列长度
            // TODO Auto-generated method stub
            return (rear - front + MAX_SIZE) % MAX_SIZE;//队列长度算法
        }
    
        @Override
        public T getHead() {
            // TODO Auto-generated method stub
            return (T) array[front];
        }
    
        @Override
        public void enQueue(T element) { //添加数据
            // TODO Auto-generated method stub
            if((rear + 1) % MAX_SIZE == front) //判断队列是否已满
                System.out.println("队列已满,无法添加");
            else {
                array[rear] = element;//数据入队
                rear = (rear + 1) % MAX_SIZE; //队尾往后移动一位
            }
        }
    
        @Override
        public T deQueue() {  //返回对头元素,并删除
            // TODO Auto-generated method stub
            if( isEmpty() )
                System.out.println("队列为空,无法删除");
            else {
                
                T temp = (T) array[front];//数据出队
                front = (front + 1) % MAX_SIZE; //队头往后移动一位
                return temp;
            }
            return null;
        }
    
        @Override
        public void queueTraverse() { //遍历
            // TODO Auto-generated method stub
            int temp = front;  //不能直接对front操作(影响结果)
            while(temp != rear) {
                System.out.print(array[temp] + " ");
                temp = (temp + 1) % MAX_SIZE;
            }
            System.out.println();
        }
    }
    
  • 代码解析
    • 队列的front,rear移动问题

      相较于栈添加和删除元素只有栈顶top移动不同,队列进队时rear向后移动,出队时front向后移动,所以当front向后移动时之前的内存就会出现浪费所以为了使rear到达数组最大值时能重新从0开始继续向后移动直到rear等于front时才达到队满状态,当进队时时应该为rear = (rear + 1) % MAX_SIZE; 出队时应该为front = (front + 1) % MAX_SIZE;

    • 队列的队空和队满的判断

      对空:front == rear
      队满:(rear + 1) % MAX_SIZE == front

链式队列

以链表为基础实现的队列

  • 代码实现
    class LinkQueue<T> implements Queue<T> {
    
        private class Node{  //节点类
            
            private Node next;
            private T dataElement;
            
            public Node() {   //构造头节点
                // TODO Auto-generated constructor stub
                this.next = null;   //节点中的next(连接下一个节点)
                this.dataElement = null;
            }
            public Node(T dataElement) {  //构造尾节点
                // TODO Auto-generated constructor stub
                this.next = null;
                this.dataElement = dataElement;
            }
        }
        
        private Node front;//队头结点
        private Node rear; //队尾结点
        private int length;
        
        public LinkQueue() { //初始化队列
            // TODO Auto-generated constructor stub
            front = new Node();
            rear = front;
            length = 0;
        }
        
        @Override
        public void destroy() {//重置结点
            // TODO Auto-generated method stub
            rear = front;
            length = 0;
        }
    
        @Override
        public boolean isEmpty() {
            // TODO Auto-generated method stub
            if(rear == front)
                return true;
            else
                return false;
        }
    
        @Override
        public int queueLength() {
            // TODO Auto-generated method stub
            return length;
        }
    
        @Override
        public T getHead() {
            // TODO Auto-generated method stub
            return front.next.dataElement;
        }
    
        @Override
        public void enQueue(T element) {//进队
            // TODO Auto-generated method stub
            Node newNode = new Node(element);
            rear.next = newNode;
            rear = newNode;
        }
    
        @Override
        public T deQueue() {//出队
            // TODO Auto-generated method stub
            //出队操作相当于删除头节点的后驱结点
            T temp = front.next.dataElement;
            front.next = front.next.next;
            return temp;
        }
    
        @Override
        public void queueTraverse() { //遍历
            // TODO Auto-generated method stub
            Node curentNode = front;
            while(curentNode != rear) {
                System.out.print( curentNode.next.dataElement + " ");
                curentNode = curentNode.next;
            }
            System.out.println();
        }
    }
    
  • 代码解析
    • 队列的入队和出队

      链队的入队和常规的后插法链表的添加一样,每次出队是将头节点的后继结点删除(先进先出)

总结

  • 栈后进先出,队列先进先出
  • 对于顺序栈base对应的是第一个元素top-1对应最后一个元素,对于链栈base.next对应第一个元素top对应最后一个元素,队列同理

你可能感兴趣的:(数据结构,队列,链表,数据结构,java)