数据结构和算法分析iOS学习笔记iOS程序猿

二叉树实现

2019-04-02  本文已影响1人  SunshineBrother

二叉树

树 是 N(N>=0)个节点的有限集。当N=0时称为空树。
在任意一棵非空树中:

树.png

结点拥有的子树树称为结点度

度为0的结点称为叶结点或者终端结点

度不为0的结点称为非终端结点或者分支结点

除根结点之外,分支节点也称为内部结点。树的度是树内部各结点的度的最大值

树1.png

节点间的关系

结点的层次从根开始定义起,根为第一层,根的孩子为第二层,依次类推

树2.png

为什么要有树结构

树结构是一种天然的组织结构,将数据使用树存储的时候,出奇的高效

我们生活中有很多树结构

树3.png 树4.png 树5.png

二叉树

二叉树的基本数据结构

class Node: NSObject {
  var E:Int 
  var left:Node?
  var right:Node?
}

二分搜索树(Binary Search Tree)

二叉树.png

二分搜索树也是一种二叉树
二分搜索树的每个节点的值

我们现在就来实现一个简单的二分搜索树吧

节点

//节点
class Node: NSObject {
    var E:Int = 0
    var left:Node?
    var right:Node?
    override init() {
        super.init()
    }
    init(E:Int) {
        self.E = E
        self.left = nil
        self.right = nil
    }
   
}

我们实现的二分搜索树实现以下功能

我们创建一个BTS类,里面有两个成员变量

var size = 0     //树的大小
var root:Node!   //根节点

1、判断树是否为空

    //判断是否为空
    func isEmpty() -> Bool{
        return size == 0;
    }

2、添加元素

    //添加元素
    func add(E:Int) {
        if root == nil {
            size += 1
            root = Node(E: E)
        }else{
            addNode(E: E, node: root)
        }
        
    }


 // 向以node为根的二分搜索树中插入元素e,递归算法
    private
    func addNode(E:Int,node:Node) {
        //递归用法,先判断结束语句
        if node.E == E {
            return
        }else if((E < node.E) && (node.left == nil)){
            //遍历到最后,添加左叶子
            node.left = Node(E: E)
            size += 1
            return
        }else if((E > node.E) && (node.right == nil)){
            //遍历到最后,添加右叶子
            node.right = Node(E: E)
            size += 1
            return
        }
        
        //递归调用
        if E < node.E {
            addNode(E: E, node: node.left ?? Node())
        }else{
            addNode(E: E, node: node.right ?? Node())
        }
        
    }

思路:

3、查看二分搜索树中是否包含某个元素

//查看二分搜索树中是否包含某个元素
func contain(E:Int) -> Bool {
        return containNode(E: E, node: root)
  }

// 看以node为根的二分搜索树中是否包含元素e, 递归算法
    private
    func containNode(E:Int,node:Node?) -> Bool {
        if node == nil {
            return false
        }
        
        if node?.E == E{
            return true
        }else if (node?.E)! > E {
            //左
            return containNode(E: E, node: node?.left )
        }else{
            //右
            return containNode(E: E, node: node?.right)
        }
        
    }

4、前序遍历、中序遍历、后序遍历

前序遍历:规则是若二叉树为空,则空操作返回,否则先访问根节点,然后前续遍历左子树,然后再前序遍历右子树

前序遍历.png
//二分搜索树的前序遍历
    func preOrder() {
        preOrder(node: root)
    }
// 前序遍历以node为根的二分搜索树, 递归算法
    private
    func preOrder(node:Node?) {
        //结束条件
        if node == nil {
            return
        }
        print(node?.E ?? "nil")
        preOrder(node: node?.left)
        preOrder(node: node?.right)
    }

中序遍历:规则是若树为空,则空操作返回,否则从根节点开始(注意并不是先访问根节点),中序遍历根节点是左子树,然后是访问根节点,最后中序遍历右子树

中序遍历.png
// 二分搜索树的中序遍历
    func inOrder() {
        inOrder(node: root)
    }
// 中序遍历以node为根的二分搜索树, 递归算法
    private
    func inOrder(node:Node?) {
        //结束条件
        if node == nil {
            return
        }
        inOrder(node: node?.left)
        print(node?.E ?? "nil")
        inOrder(node: node?.right)
        
    }

后序遍历:规则是若树为空,则空操作返回,否则从左到右先子叶后节点的方式遍历访问左右子树,最后是访问根节点

后序遍历.png
// 二分搜索树的后序遍历
func postOrder() {
    postOrder(node: root)
}

// 后序遍历以node为根的二分搜索树, 递归算法
    private
    func postOrder(node:Node?) {
        //结束条件
        if node == nil {
            return
        }
        inOrder(node: node?.left)
        inOrder(node: node?.right)
        print(node?.E ?? "nil")
    }

5、寻找二分搜索树的最小元素,删除二分搜索树的最小元素

寻找二分搜索树的最小元素

// 从二分搜索树中删除最小值所在节点, 返回最小值
   func removeMin() -> Int {
       if size == 0 {
           return 10086
       }
       root = removeMin(node: root)
       return minimum()
   }

return minimum(node: root).E
}
//查找最小数据 递归算法
   private
   func minimum(node:Node?) -> Node{
       if node?.left == nil {
           return node ?? Node()
       }
   
       return minimum(node: node?.left)
   }

思路:

删除二分搜索树的最小元素

// 从二分搜索树中删除最小值所在节点, 返回最小值
func removeMin() -> Int {
if size == 0 {
return 10086
}
root = removeMin(node: root)
return minimum()
}

// 删除掉以node为根的二分搜索树中的最小节点
// 返回删除节点后新的二分搜索树的根
private
func removeMin(node:Node?) -> Node? {
if node?.left == nil {
size -= 1
let rightNode = node?.right
node?.right = nil
return rightNode
}
node?.left = removeMin(node: node?.left)
return node
}
删除最小元素.png

思考:
在删除最小元素的时候我们需要考虑两种情况

针对上面这种,我们代码可以这样写

if node?.left == nil {
size -= 1
let rightNode = node?.right
node?.right = nil
return rightNode
}

在最小元素有有右子树的时候,我们需要把这个右子树占据我们删除的那个子树的位置

6、寻找二分搜索树的最大元素、删除二分搜索树的最大元素

寻找二分搜索树的最大元素

// 寻找二分搜索树的最大元素
func maximum() -> Int {
if size == 0 {
return 10086
}

return maximum(node: root)
}

//查找最大数据 递归算法
private
func maximum(node:Node?) -> Int {
if node?.right == nil {
return node?.E ?? 10086
}
return maximum(node: node?.right)
}

删除二分搜索树的最大元素

// 从二分搜索树中删除最大值所在节点, 返回最大值
func removeMax() -> Int {
if size == 0 {
return 10086
}
root = removeMax(node: root)
return maximum()
}

// 删除掉以node为根的二分搜索树中的最大节点
// 返回删除节点后新的二分搜索树的根
private
func removeMax(node:Node?) -> Node? {
if node?.right == nil {
size -= 1
let leftNode = node?.left
node?.left = nil
return leftNode
}
node?.right = removeMax(node: node?.right)
return node
}

7、删除任意的节点

// 删除为E的节点
func remove(E:Int) ->Node{
root = remove(E: E, node: root)
return root
}

// 删除掉以node为根的二分搜索树中值为e的节点, 递归算法
// 返回删除节点后新的二分搜索树的根
private
func remove(E:Int,node:Node?) -> Node? {
if node == nil {
return nil
}
if E < (node?.E)! {
node?.left = remove(E: E, node: node?.left)
return node
}else if E > (node?.E)! {
node?.right = remove(E: E, node: node?.right)
return node
}else{
//找到了
// 待删除节点左子树为空的情况
if node?.left == nil{
let rightNode = node?.right
node?.right = nil
size -= 1
return rightNode
}
// 待删除节点右子树为空的情况
if node?.right == nil{
let leftNode = node?.left
node?.left = nil
size -= 1
return leftNode
}
// 待删除节点左右子树均不为空的情况

// 找到比待删除节点大的最小节点, 即待删除节点右子树的最小节点
// 用这个节点顶替待删除节点的位置
let successor = minimum(node: node?.right)
successor.right = removeMin(node: node?.right)
successor.left = node?.left
node?.right = nil
node?.left = nil

return successor
}
}

思考:

// 待删除节点左子树为空的情况
if node?.left == nil{
let rightNode = node?.right
node?.right = nil
size -= 1
return rightNode
}
// 待删除节点右子树为空的情况
if node?.right == nil{
let leftNode = node?.left
node?.left = nil
size -= 1
return leftNode
}
删除任意节点1.png 删除任意节点2.png

相关demo,可以在这里查看

上一篇 下一篇

猜你喜欢

热点阅读