常见算法之队列

67 阅读3分钟

基础知识

队列是一种常用的数据结构,它最大的特点是“先入先出”,即先进入队列中的元素最先出来。这和我们日常生活中的队列一致,排在队列最前面的人优先得到服务。由于队列要保证“先入先出”的顺序,因此新的元素只能添加到队列的尾部,同时只能删除位于队列最前面的元素。

如果解决某个问题时数据的插入和删除操作满足“先入先出”的特点,那么可以考虑用队列来存储这些数据。 如滑动窗口,最近请求次数,二叉树广度优先遍历。

常见算法

一、在完全二叉树中添加节点

题目:在完全二叉树中,除最后一层之外其他层的节点都是满的(第n层有2n-1个节点)。最后一层的节点可能不满,该层所有的节点尽可能向左边靠拢。例如,图7.3中的4棵二叉树均为完全二叉树。实现数据结构CBTInserter有如下3种方法。

● 构造函数CBTInserter(TreeNode root),用一棵完全二叉树的根节点初始化该数据结构。

● 函数insert(int v)在完全二叉树中添加一个值为v的节点,并返回被插入节点的父节点。例如,在如图(a)所示的完全二叉树中添加一个值为7的节点之后,二叉树如图(b)所示,并返回节点3。在如图(b)所示的完全二叉树中添加一个值为8的节点之后,二叉树如图(c)所示,并返回节点4。在如图(c)所示的完全二叉树中添加节点9会得到如图7.3(d)所示的二叉树并返回节点4。

● 函数get_root()返回完全二叉树的根节点。

image.png

解题思路

Golang代码


type TreeNode struct {
   Val int
   Left *TreeNode
   Right *TreeNode
}


type CBTInserter struct {
   Root *TreeNode
   ParentList []*TreeNode
}


func Constructor(root *TreeNode) CBTInserter {

   list := make([]*TreeNode, 0)
   parents := make([]*TreeNode, 0)

   if root == nil {
      return CBTInserter{
         Root: root,
         ParentList: parents,
      }
   }

   list = append(list, root)

   for len(list) > 0  {
      node := list[0]

      if node.Left != nil {
         list = append(list, node.Left)
      }

      if node.Right != nil {
         list = append(list, node.Right)
      }

      if node.Left == nil || node.Right == nil {
         parents = append(parents, node)
      }

      list = list[1:]
   }

   return CBTInserter{
      Root: root,
      ParentList: parents,
   }
}

func (this *CBTInserter) Insert(v int) int {
   node := &TreeNode{Val: v}
   parent := this.ParentList[0]

   if parent.Left == nil {
      parent.Left = node
   }

   if parent.Right == nil {
      parent.Right = node
      this.ParentList = this.ParentList[1:]
   }
   this.ParentList = append(this.ParentList, node)
   return parent.Val
}


func (this *CBTInserter) Get_root() *TreeNode {
   return this.Root
}

二、二叉树中每层的最大

题目:输入一棵二叉树,请找出二叉树中每层的最大值。

解题思路

  • 使用队列做广度优先遍历
  • 用双指针,一个在一层递减,一个在下一层增,直到队列结束

Golang代码

func largestValues(root *TreeNode) []int {
   res := make([]int, 0)
   if root == nil {
      return res
   }
   var (
      one int
      two int
      max = -1 << 31
   )
   list := make([]*TreeNode, 0)
   list = append(list, root)
   one = 1

   for len(list) > 0 {

      node := list[0]
      list = list[1:]
      one--

      if node.Val > max {
         max = node.Val
      }

      if node.Left != nil {
         list = append(list, node.Left)
         two++
      }

      if node.Right != nil {
         list = append(list, node.Right)
         two++
      }

      if one <= 0 {
         one = two
         two = 0
         res = append(res, max)
         max = -1 << 31
      }
   }

   return res
}

三、二叉树最低层最左边的值

题目:如何在一棵二叉树中找出它最低层最左边节点的值?假设二叉树中最少有一个节点。

解题思路

  1. 使用队列做广度优先遍历
  2. 用双指针切片,一个在一层递减,一个在下一层增,直到队列结束,返回最后一个切片的第一个值。

Golang代码

func findBottomLeftValue(root *TreeNode) int {
   res := make([]int, 0)
   if root == nil {
      return 0
   }
   var (
      one = make([]int, 0)
      two = make([]int, 0)
   )
   list := make([]*TreeNode, 0)
   list = append(list, root)
   one = append(one, root.Val)
   res = one

   for len(list) > 0 {

      node := list[0]
      list = list[1:]
      one = one[1:]

      if node.Left != nil {
         list = append(list, node.Left)
         two = append(two, node.Left.Val)
      }

      if node.Right != nil {
         list = append(list, node.Right)
         two = append(two, node.Right.Val)
      }

      if len(one) == 0 {
         if len(two) != 0 {
            res = two
         }
         one = two
         two = []int{}

      }
   }

   return res[0]
}