数据结构和算法(四):二叉树、红黑树、递归树、堆和堆排序、堆的应

2019-11-21  本文已影响0人  冰风v落叶

从广义上来讲:数据结构就是一组数据的存储结构 , 算法就是操作数据的方法

数据结构是为算法服务的,算法是要作用在特定的数据结构上的。

10个最常用的数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie树

10个最常用的算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法

本文总结了20个最常用的数据结构和算法,不管是应付面试还是工作需要,只要集中精力攻克这20个知识点就足够了。

数据结构和算法(一):复杂度、数组、链表、栈、队列的传送门

数据结构和算法(二):递归、排序、通用排序算法的传送门

数据结构和算法(三):二分查找、跳表、散列表、哈希算法的传送门

数据结构和算法(四):二叉树、红黑树、递归树、堆和堆排序、堆的应用的传送门

数据结构和算法(五):图、深度优先搜索和广度优先搜索、字符串匹配算法、Trie树、AC自动机的传送门

数据结构和算法(六):贪心算法、分治算法、回溯算法、动态规划、拓扑排序的传送门

第十六章 二叉树

一、什么是树?
树的定义.png 树中的节点的称呼 树的高度、深度、层

小结:这里的高度和深度其实和日常工作生活中的一样的,高度其实就是从叶子到节点的距离,深度就是从根部到节点的距离。

二、什么是二叉树?
满二叉树和完全二叉树
三、如何存储一颗二叉树?

存储二叉树有两种办法,一种是基于指针的二叉链式存储法,另一种是基于数组的顺序存储法

链式存储二叉树 顺序存储法 非完全二叉树-用顺序存储法
四、如何遍历一颗二叉树?
前序、中序、后序
前序遍历的递推公式:
preOrder(r) = print r->preOrder(r->left)->preOrder(r->right)

中序遍历的递推公式:
inOrder(r) = inOrder(r->left)->print r->inOrder(r->right)

后序遍历的递推公式:
postOrder(r) = postOrder(r->left)->postOrder(r->right)->print r

五、什么是二叉查找树?
二叉查找树
六、二叉查找树与散列表的对比

我们知道,散列表的插入、删除、查找的时间复杂度都是O(1),非常高效,而二叉查找树只有在比较平衡的情况下,才能做到O(logn),那么我们为什么要用二叉查找树?

第十七章 红黑树

一、平衡二叉查找树
二、红黑树
三、红黑树的平衡调整
左旋转 右旋转
四、红黑树的插入和删除

红黑树的插入和删除比较复杂,建议大家看这篇文章,理解即可。理解了原理之后,我们就可以把红黑树的平衡调整过程,当做魔方复原的过程,按照步骤一步一步来即可。

第十八章 递归树

一、什么是递归树?
斐波那契数列的递归树
二、用递归树如何求解时间复杂度?
归并排序递归树
三、用递归树分析快速排序的时间复杂度
T(n) = 2*T(n/2) + n
     = 2*(2*T(n/4) + n/2) + n = 4*T(n/4) + 2*n
     = 4*(2*T(n/8) + n/4) + 2*n = 8*T(n/8) + 3*n
     = 8*(2*T(n/16) + n/8) + 3*n = 16*T(n/16) + 4*n
     ......
     = 2^k * T(n/2^k) + k * n
     ......

快速排序的递归树

第十九章 堆和堆排序

一、什么是堆?
二、如何存储堆?
三、堆的插入和删除
//自定义一个堆,并且插入数据
public class Heap{
    private var array:Array<Int>     //存放堆的数组
    private var maxCount: Int        //堆数组可以存储的最大个数
    private var realCount: Int = 0   //堆数组实际存储的数据个数
    
    //初始化一个堆,给定堆的容量
    public init(capacity: Int){
        array = Array(repeating: 0, count: capacity)
        maxCount = capacity
        realCount = 0
    }
    
    public func insert(data: Int){
        if realCount >= maxCount { return } //堆满了
        realCount = realCount + 1
        var i = realCount
        array[i] = data    
        // i/2代表i的父节点
        while(i / 2 > 0 && array[i] > array[i / 2]){    //当节点比其父节点小时,进行交换,这就是从下而上堆化的过程
            array.swapAt(i, i/2)
            i = i / 2
        }
    }
}

var testHeap = Heap(capacity: 10)
testHeap.insert(data: 5)
    //删除堆顶元素
    public func removeMax(){
        if realCount == 0 { return }    //如果堆中没有元素
        array[1] = array[realCount]
        realCount = realCount - 1
        heapify(array: array, realCount: realCount, i: 1)
    }
    
    private func heapify(array:Array<Int>, realCount: Int, i: Int){
        var headArray = array
        var i = i
        while true {
            if 2*i < realCount && headArray[i] < headArray[2*i]{
                //如果节点小于其左子节点
                headArray.swapAt(i, 2*i)
                i = 2*i
            }else if 2*i+1 < realCount && headArray[i] < headArray[2*i + 1]{
                //如果节点小于其右子节点
                headArray.swapAt(i, 2*i+1)
                i = 2*i + 1
            }else{
                break
            }
        }
    }
四、如何用堆实现堆排序?
五、实际开发中,为什么快速排序比堆排序性能好?

第二十章 堆的应用

堆这种数据结构有很多非常重要的应用,例如:优先级队列、求Top K、求中位数

一、优先级队列
二、利用堆求Top K
三、利用堆求中位数
上一篇 下一篇

猜你喜欢

热点阅读