数据结构

286 阅读4分钟

1. 排序 (小->大)

  • 冒泡排序:从后往前,比较两个相邻的元素,若后面比前面小,交换。每一遍遍历后都会将无序部分的最小值交换到最前面 (n*n)
  • 简单选择排序: 设置最小值下标 min ,min 初始值为最开始为当前元素(第一个元素)的下标,当前元素逐个与后面的无序部分的元素比较,若后面的元素值小,将 min 值设置为小的元素的下标值。遍历完一遍后,比较当前元素下标与 min, 若不相等,将两个坐标对应的值交换。然后追个向后遍历。(n*n)
  • 直接插入排序:从第一个元素开始,该元素认为已经被排好序。取出下一个元素,赋值给 key 。然后在已经排好序的元素中从后向前扫描,如果该元素大于 key ,将该元素后移。知道扫描到小于或等于 key 的元素,然后将 key 插入到该元素的后面。然后再取出无序的下一个元素,赋值给key 继续扫描。(n*n)
  • 希尔排序:直接插入的优化。将待排序的数组元素按下标的一定增量分组 ,分成多个子序列,然后对各个子序列进行直接插入排序算法排序;然后依次缩减增量再进行排序,直到增量为1时,进行最后一次直接插入排序,排序结束。
  • 堆排序:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
  • 归并排序:把序列中每两个相邻的元素进行归并操作,若此时序列数不是1,继续归并,直到序列书为1。归并是把两个有序序列合并成一个有序序列。通过从头开始逐个比较两个小序列元素的值,依次插入到大序列中,直到其中一个小序列全部插入进去,然后将另一个序列的值直接插入到大序列中。
  • 快速排序:冒泡排序的改进。从序列中选出一个基准值,将所有比基准值小的元素放在左边,大的放在右边。然后对左右两边的序列再进行这种排序。直到排序数列的长度为1。首先从数列的右边开始往左边找,我们设这个下标为 i,也就是进行减减操作(i--),找到第 1 个比基准数小的值,让它与基准值交换;接着从左边开始往右边找,设这个下标为 j,然后执行加加操作(j++),找到第 1 个比基准数大的值,让它与基准值交换;然后继续寻找,直到 i 与 j 相遇时结束,最后基准值所在的位置即 k 的位置

2. 查找

  • 顺序查找:从序列中第一个元素开始查找,比较,直到最后一个
  • 折半查找:有序表中,若给定值和序列中间元素相等,则查找成功。若给定值小于中间元素,则在左边区域查找,反之,去右边查找。不断重复,直到查找成功

3. 数组和链表的区别

  • 数组在内存中的空间是连续的。并且需要预留空间,在使用前要先申请占内存的大小,所以可能会浪费内存空间。插入数据和删除数据效率低。随机读取效率很高。因为数组是连续的,知道每一个数据的内存地址,可以直接找到给地址的数据。
  • 在内存中不要求连续,可以在任何地方。大小不用定义,数据随意增删。每一个数据都保存了下一个数据的内存地址,通过这个地址找到下一个数据。增加数据和删除数据很容易。查找数据时效率低,因为不具有随机访问性,所以访问某个位置的数据都要从前一个数据开始访问,然后根据前一个保存的地址找到下一个。

4. 二叉树

  • 遍历
    • 层次、先序、中序、后序
    • 递归实现:当前节点不为空,递归调用函数并将(左/右)节点传入
    • 非递归实现:以先序为例。
      • 先访问根节点,并把节点入栈。
      • 再把当前节点设置为左孩子节点,判断是否为空,若为空,栈顶节点出栈,把右孩子设置为当前节点;否则重复上面步骤
      • 直到当前节点和栈空。(栈中的节点是为了访问右孩子才储存的)