算法-图(Graph)

算法解决问题
在研究一个新的问题时,按照下面的步骤识别目标并使用数据结构抽象解决问题:

  • 1.定义API;
  • 2.根据特定的应用场景开发用例代码;
  • 3.描述一种数据结构,并在API所对应的抽象数据类型的实现中根据它定义类的实例变量;
  • 4.描述算法(实现一组操作的方式),并根据它实现类中的实例方法;
  • 5.分析算法的性能特点.

抽象数据类型
算法一般都是某个抽象数据类型的一个实例方法的实现.
抽象数据类型是一种向用例隐藏内部表示的数据类型.

实现抽象数据类型:

  • 封装
  • API设计,只为用例提供它们所需要的,仅此而已.

数据抽象的作用:

  • 1.准确的定义算法能够为用例做什么
  • 2.隔离算法的实现和用例代码
  • 3.实现多层抽象,用已知算法实现其他算法.

关于图的一些知识

  • 图:
    是由一组顶点和一组能将两个顶点相连的边组成的.
    图的定义和绘制出来的图像是无关的

泛型

集合类的抽象数据类型的一个关键特性是我们应该可以用它们存储任意类型的数据.也叫参数化类型.
泛型是指API的泛型,这样API可以面对所有的抽象数据类型定义.

算术表达式的实现问题

这是一个很有意思的问题,可以实现的方法有很多种:

  • Dijkstra算法实现,利用双栈将表达式进行一定的括号"("处理.
  • 还有一种可直接使用的就是,先将算术表达式(中缀表达式)转换成后缀表达式.利用栈的特性来计算后缀表达式.

数组表示栈,可调整数组的大小

  • 防止溢出和栈空间地址的浪费.
public void resize(int max)
{
    Item[] temp=(Item[])new object[max]; // this temp array can change size
    for (int i=0;i<N;i++) 
        temp[i]=a[i];
    a=temp;
}

public void push(Item item)
{
    if(N==a.length) resize(int N*2);// resize(2*a.length);
    a[N++]=temp;
}
public Item pop()
{
    Item item a[--N];
    a[N]=null;
    if(N>0&&N==a.length/4) resize(a.length/2);
    return item;
}

这是集合类抽象数据类型实现的模板.

链表

  • 链表是一个基础数据结构.是其他复杂数据结构构造代码的模板.

算法分析

  • 复杂度分为时间复杂度和空间复杂度:
    表示一段程序运行的效率(程序运行解决问题所用的时间和内存占用的多少)

  • 运行时间,一般是指时间复杂度
  • 占用内存,一般是指空间复杂度.
  • 具体的分析思想:我们可以构造一个数学模型来描述任意程序的运行时间.
    1.确定输入模型,定义问题的规模
    2.识别内循环
    3.根据内循环中的操作确定成本模型
    4.对于给定的输入,判断这些操作的执行频率.进行数学分析

设计算法的思路及步骤

  • 第一个比较重要的任务就是精确定义问题.
  • 数据结构的性质直接影响算法的效率.
  • 主要还是分析每个实例方法的重要性.去实现实例方法.

排序

  • 排序算法的目标就是将所有元素的主键按照某种方式排列(大小或者字母顺序)
  • 元素和主键的具体性质在不同的应用中差别很大,要注意区分
  • 除了函数调用所需的栈和固定数目的实例变量之外无需额外的内存的,原地排序算法.
  • 需要额外内存空间来进行存储的另一份数组副本的,其他排序算法.

算法之间比较的科学方法

  • 实现并调试
  • 分析它们的基本性质
  • 对相对性能作出猜想
  • 用实验验证思想
  • 具体代码实现 见SortCompare.java

选择排序

  • 整体思路:
    1.找到数组中的那个最小的元素,将它和第一个元素交换位置
    2.继续循环,找到剩余数组中的最小元素和数组的第二个元素进行交换
  • 排序特点:
    1.运行时间和输入无关
    2.数据移动是最少的,一共会有N次交换,\(\frac{N^{2}}{2}\) 次比较

插入排序

  • 整体思路:
    1.外循环先将所有的数组元素进行遍历
    2.内循环中从外循环的那个元素一直到数组的第一个元素进行进行大小的比对,交换
  • 排序特点:
    1.插入排序所需要的时间取决于输入中元素的初始顺序
    2.平均情况下插入排序需要 \(\frac{N^{2}}{4}\) 次比较 和 \(\frac{N^{2}}{4}\) 交换
    3.插入排序适用于部分有序的小规模数组
  • 部分有序数组:
    1.数组中每个元素距离它的最终位置都不太远
    2.一个有序的大数组接一个小数组
    3.数组中只有几个元素的位置不确定

希尔排序
基于插入排序的快速排序算法

  • 整体思路:
    1.交换不相邻的元素对数组的局部进行排序
    2.最终用插入排序将局部有序的数组排序
  • 具体实现:
    1.要采用跳跃分割的策略,将相距某个增量的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后的结果是基本有序而不是局部有序
    2.将关键字较小的记录,而不是一步一步的往前挪动,而是跳跃式地往前移,是得完成一轮循环后,整个序列就朝着有序迈进一步.
  • 适用范围:
    1.对于中等大小的数组运行时间是可以接受的,代码量小,且不需要使用额外的内存空间.
    2.直接接触硬件,运行于嵌入式系统中的代码等当要解决一个排序问题而又没有系统的排算法可用,可以先用希尔排序.

归并排序
利用完全二叉树来实现排序

  • 整体思路:
    利用子序列迭代归并的思想来实现归并排序
  • 抽象方法:
    原地归并的抽象方法.这个是理解算法的关键基础. 自顶向下和自底向上的归并排序的区分

快速排序
一种原地排序的分治算法

  • 整体思路:
    1.利用递归的思想,先将要排序的数组找到切分点进行分割,左侧的数组元素都小于切分点,右侧的数组元素都大于切分点.分别在再将两个数组进行递归调要排序的程序
    2.主要就是切分功能的实现
  • 切分实现:
    1.先将数组的第一个元素设置为切分点(也就是比较元素).
    2.设置两个指针,分别从数组头和数组尾进行递增递减循环
    3.当数组头的指针指向一个大于切分点的元素(不该出现在左侧的大元素),数组尾指向一个小于切分点的元素(不该出现在右侧的小元素).交换两个元素的位置.
    4.当两个指针重合时,将切分点元素和指针元素进行互换.
    需要注意,在循环的进行中要保证小指针要小于大指针
  • 知识拓展:
    注意区分三取样切分快速排序和应对于存在大量重复元素的数组的三向切分.
    当然还有一个更厉害的就是,已经有了完全不需要比较的排序算法.

优先队列

  • 概念:
    一个抽象的数据类型
    合理的分配优先级,减少不必要的操作
    支持两种基本操作,删除最大元素和插入元素.

猜你喜欢

转载自www.cnblogs.com/GeekDanny/p/9260502.html