基础算法-队列(二)

基础算法-队列(二)

理论部分为转载,算法实现部分为自己写的。

线性队列

队列同样是一种特殊的线性表,其插入和删除的操作分别在表的两端进行,队列的特点就是先进先出(First In First Out)。我们把向队列中插入元素的过程称为入队(Enqueue),删除元素的过程称为出队(Dequeue)并把允许入队的一端称为队尾,允许出的的一端称为队头,没有任何元素的队列则称为空队。

队列和栈都是一种最基础的数据结构,可以看到它们都是使用数组来实现的,也可以使用链表或其他来实现,只需要保证队列的约定就好。(栈也可以使用链表来实现)

代码实现:


public class QueueDome {

    private int front;
    private int rear;

    private int[] array;

    private int size;

    private final int ARRAY_LENGTH = 10;


    public QueueDome() {
        array = new int[ARRAY_LENGTH];
        front = 0;
        rear = 0;
        size = 0;
    }

    //入队列
    public void add(int value) {
        checkIsFull();
        array[rear++] = value;
        size++;
    }

    //出队列
    public int pull() {
        if ((front + 1) == ARRAY_LENGTH) {
            throw new RuntimeException("没有元素了");
        }
        return array[front++];
    }


    public int peek() {
        return array[front];
    }

    public boolean isFull() {
        return size > ARRAY_LENGTH;
    }

    public boolean isEmpaly() {
        return size == 0;
    }

    public void checkIsFull() {
        if (isFull()) {
            throw new RuntimeException("队列已经满了");
        }
    }


    public static void main(String args[]) {
        QueueDome dome = new QueueDome();
        dome.add(1);
        dome.add(2);
        dome.add(3);
        dome.add(4);
        dome.add(5);
        System.out.println(dome.peek());
        dome.add(6);
        dome.add(7);
        System.out.println(dome.peek());
        dome.add(8);
        System.out.println(dome.peek());
        dome.add(9);
        dome.add(10);



        System.out.println(dome.pull());
        System.out.println(dome.pull());


        System.out.println(dome.pull());
        System.out.println(dome.pull());
        System.out.println(dome.pull());
        System.out.println(dome.pull());
        System.out.println(dome.pull());
        System.out.println(dome.peek());
        System.out.println(dome.peek());

    }

解说:front指向队列头,rear指向队列尾。插入元素通过rear++来做,而读取元素通过front元素来操作。这样不就实现了一个队列嘛。
一头只能做插入动作,一头做读取操作。1元素先插入进来的,读取的时候1也是最先被读取到的。

参考地址:

http://blog.youkuaiyun.com/javazejian/article/details/53375004
参考的文章中实现了循环队列,删除的元素空出来的位置可以继续使用,其实这样会把队列的复杂度提高很多。没有多大实际意义,所以在这里就不做实现。如果要删除元素可以使用链表来实现队列,也称为链表队列这样做删除操作更好。

链式队列

链式队列就是通过链表来做的队列。

package cn.datastruts;

public class NodeQueueDome {

    private Node head;
    private Node tail;


    private int size;

    private static final int ARRAY_LENGTH = 10;

    public NodeQueueDome() {
    }

    //入队列
    public void add(int value) {
        Node node = new Node(null, value);
        if (head == null) {
            head = node;
        }

        if (tail != null) {
            tail.next = node;
        }
        tail = node;
        size++;

    }

    //出队列
    public int pull() {
        int value = -1;
        if (isEmpaly()) {
            return value;
        }

        Node t = head;
        if (t != null) {
            value = t.data;
            head = t.next;//new head
            t.next = null;//delete old head
        }
        size--;
        return value;

    }


    public int peek() {
        return head.data;
    }

    public boolean isFull() {
        return size > ARRAY_LENGTH;
    }

    public boolean isEmpaly() {
        return size == 0;
    }

    public void checkIsFull() {
        if (isFull()) {
            throw new RuntimeException("队列已经满了");
        }
    }

    private static class Node {
        Node next;
        int data;


        public Node(Node next, int data) {
            this.next = next;
            this.data = data;
        }
    }


    public static void main(String args[]) {
        NodeQueueDome dome = new NodeQueueDome();
        for (int i = 0; i < 10; i++) {
            dome.add(i + 1);
        }

        while (!dome.isEmpaly()) {
            System.out.println(dome.pull());
        }


    }

}

链表中添加节点图解:

苦笑不得两行代码,都开始怀疑自己不是搞java开发的了。
当tail!=null时
tail.next=node;
tail=node;
当时这两句把我给绕晕了,我的理解是

tail=node,然后tail.next也指向了node,我就以为是node自己指向了自己。
第一步:其实忘记了tail刚开始是指向head这个节点的,tail.next改变了了值,则head的值也跟着改变了,所以head.next也指向了node。
第二步:tail=node。相当于 tail = new Node(null,value);tail已经和前面的head节点没有关系了,现在的tail.next等于null了。

写代码写多了把自己给搞晕了。
tail=node;
head=node;
tail.next= node2;
这样修改会把head的next也跟着修改了,因为它们引用的是同一个对象,tail.next修改的是它们共同的对象node的next,所以一处修改大家一起跟着变了。

修改同一个引用的对象的属性,被引用的对象的属性变了,引用的属性也跟着变了。

tail = node ;
head = node;
tail = node2;
这样是不会把head 也跟着修改的。因为tail是修改了自己的引用,把tail自己的引用修改为node2了。

修改自己的引用地址,仅此而已。代码看多了,把自己给看晕了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值