数据结构之栈和队列

栈和队列是计算机中基本的两个数据结构,栈可以达到后进先出,队列可以先进先出。在实际应用上,我们可以使用栈进行逆序遍历链表,非递归中序遍历二叉树,括号匹配,函数调用等等;可以使用队列对二叉树进行层次遍历,打印机的打印服务,通信中的消息队列等等。

 

下面贴几道关于栈和队列较常考的笔试/面试题。

链表逆序遍历:思想很简单,当链表节点不为null就进行压栈,直到为null。

class Node2{
    int value;
    Node2 next;
}
    
public void reservePrintList(Node2 root) {
        
    if (root == null) {
        return;
    }
        
    Stack<Node2> stack = new Stack<>();
    while (root !=null) {
        stack.push(root);
        root = root.next;
    }
        
    while (!stack.isEmpty()) {
        System.out.println(stack.pop().value);
    }
}

 

非递归中序遍历二叉树:中序遍历二叉树第一个被遍历的节点肯定位于二叉树的最左边,在未到最左边之前一直压栈,到了就出栈。

class Node{
    int value;
    Node left;
    Node right;
}
/**
 * 非递归中序遍历二叉树,利用栈可以很方便的实现
 * @param root
 */
public void printTree1(Node root) {
        
    if (root == null) {
        return;
    }
        
    Stack<Node> stack = new Stack<>();
    while (root != null) {
        stack.push(root);  // 根节点压栈
        if (root.left != null) { // 左子树不为空,将左子树压入栈
            stack.push(root.left);
        }else {
            // root的左子树为空,说明root要么是叶子,要么是还有右子树,不管是叶子还是有右子树的节点,它都将进行输出
            // 因为中序遍历的的顺序是从左到右
            Node node = stack.pop(); 
            System.out.println(node.value);
            if (node.right != null) {
                // 存在右子树,将右子节点压栈,因为不清楚右子节点是否为叶子,所以是压栈进行下一轮循环进行处理
                stack.push(node.right);
            }
                
            root = stack.peek(); // 取栈顶元素,但不移除,因为不清楚目前栈顶节点是否为叶子
        }
    }
        
}

 

二叉树层次遍历:层次遍历值对二叉树从上到下进行一层层的遍历,每层的遍历顺序为从左到右,借助队列可以很容易实现

class Node{
        int value;
        Node left;
        Node right;
}
/**
* 层次遍历二叉树(从上到下),借助队列这一数据结构可以很好的实现
* @param root
*/
public void printTree2(Node root) {
        
    if (root == null) {
        return;
    }
        
    Queue<Node> queue = new LinkedList<>();
    queue.add(root); // 将根节点加入队列
    while (root != null) {
        Node node = queue.poll(); // 取出队头root
        if (node.left != null) { // 左子节点不为空,入队
            queue.offer(root.left);
        }
        if (node.right != null) { // 右子节点不为空 ,入队
            queue.offer(root.right);
        }
        System.out.println(node.value); // 打印队头元素
        root = queue.peek();    // 获取新的队头元素,但不移除,更新为root
    }
}

 

看师弟师妹们数据机构第三章的总结,都是自行实现栈和队列这两个数据结构,我上面贴出的代码没有进行栈或队列满的判断,这是因为我偷懒直接使用java类库,java类库里的栈或队列都是在超过初始容量后自动扩容的(最大容量好像int类型最大的整数)。C++也是直接把栈和队列封装好可以直接使用,但是在学习的时候建议还是先理解底层原理,自己实现,等底层原理熟练就直接用封装好的类,还有就是建议师弟师妹们要多去敲代码,不能说基本理论原理了解了,就不去使用代码进行实现,理论和代码实现还是有一定差别的,在代码实现过程中,可能会出现一些bug,不要怕bug,虽然bug的确很烦,一个引用出错就找了几小时(我的惨痛经历),但是解决bug后下次我们就可以更好的避免同类型的bug了。

  

posted @ 2019-04-09 20:19  X_huang  阅读(855)  评论(4编辑  收藏  举报