栈与队列

栈与队列

队列:

队列是典型的 FIFO 数据结构。插入(insert)操作也称作入队(enqueue),新元素始终被添加在队列的末尾。 删除(delete)操作也被称为出队(dequeue)。 你只能移除第一个元素。

下面是使用内置队列库及其常见操作的一些示例:

// "static void main" must be defined in a public class.
public class Main {
    public static void main(String[] args) {
        // 1. Initialize a queue.
        //初始化一个队列
        Queue<Integer> q = new LinkedList();
        // 2. Get the first element - return null if queue is empty.
        //得到第一个元素,如果队列为空则返回null
        System.out.println("The first element is: " + q.peek());
        // 3. Push new element.
        //入队
        q.offer(5);
        q.offer(13);
        // 4. Pop an element.
        //出队
        q.poll();
        // 5. Get the first element.
        //得到第一个元素
        System.out.println("The first element is: " + q.peek());
        // 7. Get the size of the queue.
        //得到队列长度
        System.out.println("The size is: " + q.size());
    }
}

广度优先搜索(BFS)

广度优先搜索的一个常见应用是找出从根结点到目标结点的最短路径
BFS 的两个主要方案:遍历或找出最短路径
模板一

/**
 * Return the length of the shortest path between root and target node.
 */
int BFS(Node root, Node target) {
    // store all nodes which are waiting to be processed
    //存储所有等待被操作的节点
    Queue<Node> queue;  
    // number of steps neeeded from root to current node
    //记录从根到当前节点的步数
    int step = 0;       
    // initialize
    //初始化
    add root to queue;//将根加入队列中
    // BFS广度优先搜索
    while (queue is not empty) {//队列不为空
        step = step + 1;
        // iterate the nodes which are already in the queue
        //迭代遍历已经在队列中的节点
        int size = queue.size();
        for (int i = 0; i < size; ++i) {
            Node cur = the first node in queue;//让cur指向当前队列中的第一个节点
            return step if cur is target;//如果cur指向的是目标节点,则返回步数
            for (Node next : the neighbors of cur) {//遍历cur的所有邻居
                add next to queue;//将邻居添加到队列中
            }
            remove the first node from queue;//将第一个节点从队列中移除
        }
    }
    // there is no path from root to target
    //如果没有从根节点到目标节点的路径则返回-1
    return -1;          
}

模板二
有时,确保我们永远不会访问一个结点两次很重要。否则,我们可能陷入无限循环。如果是这样,我们可以在上面的代码中添加一个哈希集来解决这个问题。这是修改后的伪代码:

/**
 * Return the length of the shortest path between root and target node.
 */
int BFS(Node root, Node target) {
    // store all nodes which are waiting to be processed
    //存储所有等待被操作的节点
    Queue<Node> queue;  
    // store all the used nodes
    //存储所有用过的节点
    Set<Node> used;     
    // number of steps neeeded from root to current node
    //从根节点到当前节点所需要的步数
    int step = 0;      
    // initialize
    //初始化
    add root to queue;//将根节点添加到队列中
    add root to used;//将根节点添加到hash数组中
    // BFS
    while (queue is not empty) {
        step = step + 1;
        // iterate the nodes which are already in the queue
        //迭代遍历已经在队列中的节点
        int size = queue.size();
        for (int i = 0; i < size; ++i) {
            Node cur = the first node in queue;
            return step if cur is target;
            for (Node next : the neighbors of cur) {
                if (next is not in used) {//如果邻居不存在于hash数组中,即未被使用过
                    add next to queue;
                    add next to used;
                }
            }
            remove the first node from queue;
        }
    }
    return -1;          // there is no path from root to target
}

例题
LeetCode200 岛屿数量(Java)
LeetCode752. 打开转盘锁(Java)
LeetCode 365. 水壶问题(Java)
LeetCode 279. 完全平方数(Java)
LeetCode 1162. 地图分析(Java)

后入先出的数据结构。
栈是一个 LIFO 数据结构。通常,插入操作在栈中被称作入栈 push 。与队列类似,总是在堆栈的末尾添加一个新元素。但是,删除操作,退栈 pop ,将始终删除队列中相对于它的最后一个元素。

参考的代码示例

// "static void main" must be defined in a public class.
public class Main {
    public static void main(String[] args) {
        // 1. Initialize a stack.
        //初始化一个栈
        Stack<Integer> s = new Stack<>();
        // 2. Push new element.
        //入栈
        s.push(5);
        s.push(13);
        s.push(8);
        s.push(6);
        // 3. Check if stack is empty.
        //判断栈是否为空
        if (s.empty() == true) {
            System.out.println("Stack is empty!");
            return;
        }
        // 4. Pop an element.
        //出栈
        s.pop();
        // 5. Get the top element.
        //得到栈顶元素
        System.out.println("The top element is: " + s.peek());
        // 6. Get the size of the stack.
        //得到栈的大小
        System.out.println("The size is: " + s.size());
    }
}

例题
LeetCode 155. 最小栈(Java)
LeetCode 20. 有效的括号(Java)
LeetCode 739. 每日温度(Java)
LeetCode 150. 逆波兰表达式求值(Java)

深度优先搜索(DFS)

与 BFS 类似,深度优先搜索(DFS)也可用于查找从根结点到目标结点的路径。
DFS 的递归模板

/*
 * Return true if there is a path from cur to target.
 */
boolean DFS(Node cur, Node target, Set<Node> visited) {
    return true if cur is target;
    for (next : each neighbor of cur) {
        if (next is not in visited) {
            add next to visted;
            return true if DFS(next, target, visited) == true;
        }
    }
    return false;
}

例题:
LeetCode200 岛屿数量(Java)
LeetCode 133. 克隆图(Java)
LeetCode 494. 目标和(Java)

使用显式栈的模板

/*
 * Return true if there is a path from cur to target.
 */
boolean DFS(int root, int target) {
    Set<Node> visited;
    Stack<Node> s;
    add root to s;
    while (s is not empty) {
        Node cur = the top element in s;
        return true if cur is target;
        for (Node next : the neighbors of cur) {
            if (next is not in visited) {
                add next to s;
                add next to visited;
            }
        }
        remove cur from s;
    }
    return false;
}

例题
LeetCode 94. 二叉树的中序遍历(Java)
总结习题
LeetCode 232. 用栈实现队列(Java)
LeetCode 225. 用队列实现栈(Java)
LeetCode 394. 字符串解码(Java)
LeetCode 733. 图像渲染(Java)
LeetCode 542. 01 矩阵(Java)
LeetCode 841. 钥匙和房间(Java)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值