数据结构

堆和堆排序

要讲堆排序之前,首先就要先讲讲选择排序,堆排序在思路上实际上是选择排序是一致的。
先简单总结一下各种排序:
1. 插入排序,类比城插入牌一样,认为前面的数已经排好序了,遍历到新的数,把它插入到它应该在的位置。
2. 选择排序,每次都遍历数组,选择 未排序部分最大或最小的数字,把最小或最大的数放到最前面,然后剩下的往后各移一位
3. 冒泡排序,基本思想是將比較大的數字沉在最下面,较小的浮在上面。

堆排序实际上也是逐步选择未排序数组中最大或者最小的值,来进行排序。那么他比选择排序好在哪呢,在于他利用大顶堆或者小顶堆的结构特性加快了选择的速度。

堆结构

堆可以抽象地理解成二叉树的结构,但是只需要用数组进行存储,父节点的值总是大于或等于左右子节点的值(大顶堆)。注意到,在数组中,如果位置k为父节点,那么其左右子节点位置在 2k 和 2k+1 !!!!

如何把无序数组重构成堆有序的数组

检查所有父节点,即nums[1:length/2]当发现父节点比子节点小的时候,要将父子节点交换,即父节点下沉。

void heap(vector<int> &nums,int n){
    //n表示带排列数组的长度
    //检查所有父节点,即```nums[1:length/2]```当发现父节点比子节点小的时候,要将父节点和左右子节点中较大的那个交换,即父节点下沉。
    for(int k=n/2;k>=1;k--)
        sink(nums,k,n);
    return;
}
void sink(int* nums,int parentIndex, int numsSize){
    while(2*k<=n){
        int j=2*k;
        //找到子节点较大的那个
        if(j<n && nums[j]<nums[j+1]) j++;
        //如果下沉过程中,出现父节点大于等于左右子节点则停止下沉
        if(nums[k]>=nums[j]) break;
        //将父子节点贾环,完成下沉
        swap(nums[k],nums[j]);
        //换完之后,更改父节点位置,继续下沉
        k=j;
    }
}

将堆有序的数组正确排序

将堆有序数组的第一位,也就是根节点(最大值)与最后一位交换,然后对除最后一位以外的数组重新构造堆有序数组。然后不断取出最大值也就是根节点。

void heapSort(vector<int>& nums){
    int n=nums.size();
    //初次堆排序
    heap(nums, n);
    //依次取出最大值
    while(n>1){
        swap(nums[1],nums[n--]);
        //重新堆排序
        sink(nums,1,n);
    }
}

优先队列

优先队列是一种变形的队列,先进但是永远是最大的数先出。每次放入一个数加入到数组最后,然后不断将其上浮(或者上述的下沉算法,直到所有的值都堆有序),顶部的值就可以一直保持是最大值。

哈希表

对于数据而言,最重要的操作就是查找,插入,删除等等。数组由于其在内存中是连续存储的,所以可以通过索引在O(1)的时间内取到数据,而链表由于存储地址不连续,需要遍历,最坏需要O(n)的时间。但是对于插入而言,链表的优势却又很大。

HashTable的本质还是用数组存储数据,但如何能够做到快速插入和删除呢?

思想是通过一个函数,对给定的key做函数映射,得到一个整数,然后将该数字对要存储数据的数组长度取余,得到的结果就是存储value的数组下标。所以插入,查找,删除都只需要接近O(1)的时间。

但是一个很重要的问题是如何避免散列冲突? 即映射结果相同怎么办?

  1. Java的HashMap使用的拉链法
    数组里存链表,一旦遇到映射出来的下标已经被占用,则把该值附到链表的尾部
    image

  2. 建立一个缓冲区,把凡是拼音重复的人放到缓冲区中。当我通过名字查找人时,发现找的不对,就在缓冲区里找。

  3. 进行再探测。就是在其他地方查找。探测的方法也可以有很多种。

    3.1 在找到查找位置的index的index-1,index+1位置查找,index-2,index+2查找,依次类推。这种方法称为线性再探测。

    3.2 在查找位置index周围随机的查找。称为随机在探测。

    3.3 再哈希。就是当冲突时,采用另外一种映射方式来查找。

二叉树

二叉树的遍历

  1. 前序遍历
    def preorderTraversal(self, root):
        results = []
        self.frontIter(root, results)
        return results

    def frontIter(self, root, results):
        if root:
            results.append(root.val)
            self.frontIter(root.left, results)
            self.frontIter(root.right, results)
  1. 中序遍历

  2. 后序遍历

  3. 层次遍历

搜索二叉树

平衡二叉树

红黑树

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值