X16数据结构部分01

队列代码实现:

package dc;

import java.util.List;
import java.util.ArrayList;

/**
 * @author 404小恐龙
 * @version 1.8
 * @date 2021/10/2 09:42
 */
public class d11{
    public static void main(String[] args) {
        MyQueue q = new MyQueue();
        q.enQueue(5);
        q.enQueue(3);
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
        q.deQueue();
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
        q.deQueue();
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
    }
}

class MyQueue {
    // store elements
    private List<Integer> data;
    // 指针指向队列的头部
    private int p_start;
    public MyQueue() {
        data = new ArrayList<Integer>();
        p_start = 0;
    }

    /**
     * 元素入队
     * @param x 入队元素
     * @return 操作成功
     */
    public boolean enQueue(int x) {
        data.add(x);
        return true;
    }

    /**
     * 元素出队
     * @return 出队是否成功
     */
    public boolean deQueue() {
        if (isEmpty() == true) {
            return false;
        }
        /*
        队头指针指向下一个元素的索引
         */
        p_start++;
        return true;
    }

    /**
     * 获取队头元素
     * @return 队头元素
     */
    public int Front() {
        return data.get(p_start);
    }

    /**
     * 队列是否为空
     * @return boolean 是否为空
     */
    public boolean isEmpty() {
        return p_start >= data.size();
    }
}
/*
上面的实现很简单,但在某些情况下效率很低。 
随着起始指针的移动,浪费了越来越多的空间。
当我们有空间限制时,这将是难以接受的。
这里给出了解决此类问题的方案:
https://leetcode-cn.com/leetbook/read/queue-stack/kgtj7/
动态数组+头部指针 实现的队列,在出队入队操作中,无法重复利用出队释放的空间,所以会浪费空间。
固定数组+头尾双指针 实现循环队列,可以重复利用出队释放的空间,解决空间浪费的问题

问题:如果固定数组满了之后,我还需要入队,而不是让其他出队,这是不是他的弊端,这种情况应该怎么做呢
回答:这个时候可以考虑扩容机制
*/

循环队列代码实现:

/**
 * @author 404小恐龙
 * @version 1.8
 * @date 2021/10/2 09:56
 */
class MyCircularQueue {
    private int[] mContainer;

    private int mContainerSize;

    private int mHead;

    private int mTail;


    public MyCircularQueue(int k) {
        mContainerSize = k;
        mContainer = new int[k];
        mHead = -1;
        mTail = -1;
    }

    /**
     * 元素入队
     * @param value 入队元素
     * @return 入队是否成功
     */
    public boolean enQueue(int value) {
        if(isFull()) {
            return false;
        }
        if(isEmpty()) {
            mHead ++;
            mTail ++;
            mContainer[mTail] = value;
            return true;
        }
        mTail ++;
        if(mTail > mContainerSize-1) {
            /*
            尾指针拐回来
             */
            mTail = mTail-mContainerSize;
        }
        mContainer[mTail] = value;
        return true;
    }

    /**
     * 元素出队
     * @return 出队是否成功
     */
    public boolean deQueue() {
        if(isEmpty()) {
            return false;
        }
        /*
        这种情况下
        循环数组中还剩最后一个元素
        进入该条件语句
        返回true
        就不会执行下面的语句了
         */
        if(mHead == mTail) {
            mHead = -1;
            mTail = -1;
            return true;
        }
        mHead ++;
        if(mHead > mContainerSize-1) {
            mHead = mHead-mContainerSize;
        }
        return true;
    }

    public int Front() {
        if(isEmpty()) {
            return -1;
        }
        return mContainer[mHead];
    }

    public int Rear() {
        if(isEmpty()) {
            return -1;
        }
        return mContainer[mTail];
    }

    public boolean isEmpty() {
        return mHead == -1 && mTail == -1;
    }

    public boolean isFull() {
        if(mContainerSize == 0) {
            return true;
        }
        if(mHead == -1 && mTail == -1) {
            return false;
        }
        return (mTail-mHead+1 == mContainerSize) || (mTail-mHead == -1);
    }
}

循环队列官方代码实现:

/**
 * @author 404小恐龙
 * @version 1.8
 * @date 2021/10/2 10:00
 */
class MyCircularQueue {
    
    private int[] data;
    private int head;
    private int tail;
    private int size;

    /** Initialize your data structure here. Set the size of the queue to be k. */
    public MyCircularQueue(int k) {
        data = new int[k];
        head = -1;
        tail = -1;
        size = k;
    }
    
    /** Insert an element into the circular queue. Return true if the operation is successful. */
    public boolean enQueue(int value) {
        if (isFull() == true) {
            return false;
        }
        if (isEmpty() == true) {
            head = 0;
        }
        tail = (tail + 1) % size;
        data[tail] = value;
        return true;
    }
    
    /** Delete an element from the circular queue. Return true if the operation is successful. */
    public boolean deQueue() {
        if (isEmpty() == true) {
            return false;
        }
        if (head == tail) {
            head = -1;
            tail = -1;
            return true;
        }
        head = (head + 1) % size;
        return true;
    }
    
    /** Get the front item from the queue. */
    public int Front() {
        if (isEmpty() == true) {
            return -1;
        }
        return data[head];
    }
    
    /** Get the last item from the queue. */
    public int Rear() {
        if (isEmpty() == true) {
            return -1;
        }
        return data[tail];
    }
    
    /** Checks whether the circular queue is empty or not. */
    public boolean isEmpty() {
        return head == -1;
    }
    
    /** Checks whether the circular queue is full or not. */
    public boolean isFull() {
        return ((tail + 1) % size) == head;
    }
}

双栈模拟队列:

public class d746 {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();

    /**
     * 压栈的方法
     * @param node 被压入的元素
     */
    public void push(int node) {
        stack1.push(node);
    }

    /**
     * 弹栈的方法
     * @return 原先stack1被压入的第一个元素
     */
    public int pop() {
        if (stack2.empty()) {
            /*
            核心部分:
            清空stack1
            清空一次在stack2中压入相同的元素
            返回压入的最后一个元素
            便是原先stack1压入的第一个元素
             */
            while (!stack1.empty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
}

队列思想解决数据流的移动平均值:

package dc;

import java.util.LinkedList;
import java.util.Queue;

/**
 * @author 404小恐龙
 * @version 1.8
 * @date 2021/10/2 10:05
 */
public class d13 {
    /*
    需求:数据流的移动平均值
    MovingAverage m = new MovingAverage(3);
    m.next(1) = 1
    m.next(10) = (1 + 10) / 2
    m.next(3) = (1 + 10 + 3) / 3
    m.next(5) = (10 + 3 + 5) / 3
     */
    public static void main(String[] args) {
        MovingAverage m = new MovingAverage(3);
        System.out.println(m.next(1));
        System.out.println(m.next(10));
        System.out.println(m.next(3));
        System.out.println(m.next(5));
    }
}



/**
 * 使用队列的思想来解决滑动平均问题
 */
class MovingAverage {
    private Queue<Integer> queue;
    /*
    移动窗口的范围
     */
    private int maxSize;

    //Initialize your data structure here.
    public MovingAverage(int Size) {
        queue = new LinkedList<Integer>();
        maxSize = Size;
    }

    public double next(int value){
        int sum = 0;
        if(queue.size()>=maxSize){
            /*
            移除头元素
            添加新元素
             */
            queue.poll();
            queue.offer(value);
        } else{
            queue.offer(value);
        }
        for(Integer x:queue){
            sum+=x;
        }
        return (sum*1.0)/queue.size();
    }
}

队列思想解决墙与门算法:最短路径模板

package dc;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Arrays;
import java.util.List;

/**
 * @author 404小恐龙
 * @version 1.8
 * @date 2021/10/2 10:20
 */
public class d14 {
    /*
    队列的广度优先搜索
        与树的层序遍历相同,是优化过后的BFS
        同一层节点将在同一个循环中处理,保证每次循环结束时队列中都是同一层的元素
        正好之前遇到过类似求最短路径的问题
        层序遍历能按层,遍历到所有的节点,在此基础上求出最短路径
        而深度优先类似与二叉树的中序遍历

    补充一下队列知识:
        // 移除队列头元素
        queue.remove(); // 如果队列为空,会报 NoSuchElementException 异常
        queue.poll();  // 如果队列为空,会返回null

        // 添加元素
        queue.add(1); // 如果队列满会报unchecked异常
        queue.offer(1); // 如果队列满会返回false

        // 在不移除的情况下返回队列头
        queue.peek(); // 如果队列空,返回null
        queue.element(); // 如果队列空,会报 NoSuchElementException 异常

     */
    public static void main(String[] args) {
    }
}

class Solution {
    /*
    墙与门
    题目描述:
        您将获得一个由这三个可能值初始化的m x n 2d网格。less
        -1 - 墙  可以想象成障碍物
        0 - 门   可以想象成目的地
        INF - 空房间   可以想象成起点
        这个程序可以封装成求最短路径算法

        INF - 无限意味着一个空房间。咱们使用值2^31-1=2147483647表示inf,
        于您能够假定到门的距离小于2147483647。
        把每一个空房间填满到最近的门的距离。若是不可能到达一个门,应该用inf填充。
        函数把每一个空房间填满到最近的门的距离。若是不可能到达一个门,应该用inf填充。
        在程序中,我使用EMPTY表示空房间
     */
    private static final int EMPTY = Integer.MAX_VALUE;
    private static final int GATE = 0;
    /*
    初始化坐标轴
    x:1表示向下,-1表示向上
    y:1表示向右,-1表示向左
     */
    private static final List<int[]> DIRECTIONS = Arrays.asList(
            new int[] { 1,  0},
            new int[] {-1,  0},
            new int[] { 0,  1},
            new int[] { 0, -1}
    );

    public void wallsAndGates(int[][] rooms) {
        /*
        m表示行数
        n表示列数
         */
        int m = rooms.length;
        if (m == 0) return;
        int n = rooms[0].length;
        /*
        所有的门入队
         */
        Queue<int[]> q = new LinkedList<>();
        for (int row = 0; row < m; row++) {
            for (int col = 0; col < n; col++) {
                if (rooms[row][col] == GATE) {
                    q.add(new int[] { row, col });
                }
            }
        }
        /*
        广度优先遍历开始
         */
        while (!q.isEmpty()) {
            /*
            获取当前门的行列坐标
             */
            int[] point = q.poll();
            int row = point[0];
            int col = point[1];
            /*
            分别从上下左右四个方向进行排查
             */
            for (int[] direction : DIRECTIONS) {
                int r = row + direction[0];
                int c = col + direction[1];
                /*
                如果超出边界或者它不是空房间(EMPTY)
                跳过此次循环
                下面两行代码不执行
                 */
                if (r < 0 || c < 0 || r >= m || c >= n || rooms[r][c] != EMPTY) {
                    continue;
                }
                /*
                程序运行到此处
                说明找到了空房间
                这里的rooms[r][c]就是
                二维数组中的INF
                此时房间离门的距离+1
                再次放入队列等待处理
                 */
                rooms[r][c] = rooms[row][col] + 1;
                q.add(new int[] { r, c });
            }
        }
    }
}

岛屿问题:深度优先搜索解决

class Solution1 {
    private int count = 0;

    /**
     * 有多少个岛屿
     * @param grid 二维数组
     * @return 多少个岛屿
     */
    public int numIslands(char[][] grid) {
        if(grid.length == 0 || grid[0].length == 0){
            return count;
        }
        /*
        得到二位数字的行数和列数
         */
        int m = grid.length;
        int n = grid[0].length;
        /*
        遍历查找当前为1的元素
         */
        for(int i=0;i < m;i++){
            for(int j=0;j < n;j++){
                if(grid[i][j] == '1'){
                    /*
                    程序运行到此处
                    开始递归查询
                    向四个方向扩散查找
                    直到查找完毕执行count++
                     */
                    dfs(grid, i, j);
                    count++;
                }
            }
        }
        return count;
    }

    /**
     * 上下左右方向查询
     * @param grid 二维数组
     * @param i 当前元素所在行
     * @param j 当前元素所在列
     */
    public void dfs(char[][] grid, int i, int j){
        if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == '0'){
            return;
        }
        /*
        访问过的grid设置为0
        避免出现死循环
         */
        grid[i][j] = '0';
        dfs(grid, i - 1, j);
        dfs(grid, i + 1, j);
        dfs(grid, i, j - 1);
        dfs(grid, i, j + 1);
    }
}

总目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

muskfans

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值