《数据结构》课程绪论

来源:互联网 发布:linux count 命令 编辑:程序博客网 时间:2024/05/20 01:46

《数据结构》课程绪论

使用教材:

《数据结构教程》第5版 李春葆 清华大学出版社

参考书:

《数据结构与算法分析 C语言描述》(第2版) Mark Allen Weiss 机械工业出版社
《算法导论》(第3版) Charles E. Leiserson 等 机械工业出版社
《算法》(第4版) Robert Sedgewick Kevin Wayne 人民邮电出版社
《STL源码剖析》 侯捷 华中科技大学出版社

使用语言:C/C++

1.数据结构基本概念

数据与数据结构

  • 数据(data):描述客观事物的数和字符的集合。
  • 数据元素(data element):数据的基本单位
  • 数据项(data item):具有独立含义的数据最小单位,又叫字段或域。
  • 数据结构(data structure):所有数据元素及其构成的关系

数据结构包括的三个方面

  • 逻辑结构(logical structure)(数据的逻辑关系)
  • 存储结构(storage structure)(物理结构,如何在存储器上表示)
  • 运算(operation)(对数据实施的操作,增删改查排序等)

逻辑结构的表示方法

  • 图表
  • 二元组B=(D,R),其中D为数据集合,R为数据的所有关系的集合
  • 每一个关系是序偶的集合,对于序偶<x,y>(x,yD),xy的前驱(predecessor),yx的后继(successor)。使用尖括号表示xy是一个偏序关系,圆括号表示为等价关系。

逻辑结构的类型

  • 集合
  • 线性结构
  • 树形结构
  • 图型结构

存储结构

处理存储结构,既要保证存储所有的元素xD,也要存储数据之间的逻辑关系rR
1. 顺序存储结构:所有元素在存储器中都是连续存放的,逻辑相邻的元素也必然物理相邻。支持快速的查找,插入和删除较慢;
2. 链式存储结构:每个逻辑元素使用内存中的结点存储。所有结点的地址不一定是连续的。C/C++使用指针来链接每一个结点。Java等语言使用引用。支持快速的插入和删除,但是不能随机存取,需要额外浪费指针空间。
3. 索引存储结构:利用关键字,地址的方式建立索引,可以利用关键字的有序性快速查找到关键字地址。查找效率高,但是索引表需要额外空间开销。
4. 哈希(散列)存储结构:直接建立值->存储地址的映射,支持快速查找和插入,不存储数据之间的逻辑关系。

2.算法及其分析

算法的特点

  • 有穷性
  • 确定性
  • 可行性
  • 有输入输出

算法设计的目标

  • 正确性
  • 可使用性
  • 可读性
  • 健壮性
  • 高效率、低存储

算法的时间分析

T(n)表示元操作出现的频度(注意是实际执行的次数,例如求一个数n的所有因子,只需要判断t[1,n]是不是其因子即可,如果是则tn/t都是其因子,因此其内层的判断语句实际执行的次数是n次,因此时间复杂度为O(n)
通常用“大O记号”表示其渐进复杂度。渐进复杂度取其最高阶,忽略系数和低阶项。

最好、最坏、平均时间复杂度

设输入规模n,所有输入实例的集合为DI表示输入。
平均时间复杂度的定义E(n)=P(I)T(I),ID
最好时间复杂度:B(n)=min{T(n)},ID,
最坏时间复杂度:W(n)=max{T(n)},ID.

递归算法分析

先求出递归式,然后对其化简,或使用递归树、主定理等方法。

算法复杂度分析举例

二分查找最坏情况
/*** 二分查找(升序数组中查找)* @param int[] A 待查找的数组* @param int length 数组的长度* @param int value 待查找的元素* @return int 该元素在数组中的下标(0开始,未找到则返回-1)*/int binary_search(int A[], int length, int value) {    int begin = 0, end = length - 1, mid;    while (begin <= end) {        mid = (begin + end) / 2;        if (A[mid] == value)            return mid;        else if (A[mid] > value)            end = mid - 1;        else            begin = mid + 1;    }    return -1;}

二分查找的核心语句是while循环。
最坏情况下,数组A中没有值为value的元素,不妨设A={a1,a2,...,an},且a1<a2<...<an个元素(n2n2

第二次比较后剩余N2=n212个元素(n212n22),…,

最后一次(第k次)比较剩余Nk=1个元素,又Nkn2k,于是n2k1,故2kn,解得klog2n。其他情况同理。
因此最坏情况下的时间复杂度为O(log2n)

选择排序
/*** 选择排序(升序)* @param int[] A 待排序数组* @param int length 数组长度* @return int 函数返回值,0表示成功*/int selection_sort(int A[], int length){    int i, j;    int min, tmp;    for (i = 0; i < length - 1; i++) {          min = i;        for (j = i + 1; j < length; j++)            if (A[min] > A[j])                min = j;        tmp = A[i];        A[i] = A[min];        A[min] = tmp;    }    return 0;}

核心语句是一条if判断语句,
对于外层for循环,执行n次;
内层for循环,执行(n1)+(n2)+...+1=n22次;
因此其时间复杂度是O(n×n22)=O(n2)

二路归并排序
/*** 二路归并排序* @param int[] A 待排序数组* @param int length 数组长度* @return int 函数返回值,0成功*/int merge_sort(int A[], int length) {    int * aux = (int *)malloc(sizeof(int) * length);    merge_sort_sub(A, 0, length - 1, aux);    return 0;}/*** 二路归并排序子函数* @param int[] A 源数组* @param int begin 当前排序的子数组的起始下标* @param int end 当前排序的子数组的结束下标* @param int[] aux 临时数组*/int merge_sort_sub(int A[], int begin, int end, int aux[]) {    int midpoint;    int i, j, k;    if (end <= begin)        return;    midpoint = (end + begin) / 2;    merge_sort_sub(A, begin, midpoint, aux);    merge_sort_sub(A, midpoint + 1, end, aux);    for (k = begin; k <= end; k++)        aux[k] = A[k];    i = begin;    j = midpoint + 1;    for (k = begin; k <= end; k++) {        if (i <= midpoint && j <= end) {            if (aux[i] > aux[j])                A[k] = aux[j++];            else                A[k] = aux[i++];        }        else if (i > midpoint) {            A[k] = aux[j++];        }        else if (j > end) {            A[k] = aux[i++];        }    }    return 0;}

在递归过程中,设merge_sort_sub一个长度为n的数组需要的执行频度为T(n)
merge_sort_sub(A, begin, midpoint, aux)贡献为T(n2)
merge_sort_sub(A, midpoint + 1, end, aux)的贡献为T(n2)
最后需要对n个元素进行归并,贡献为n
因此有递归式T(n)=T(n2)+T(n2)+n
假设n2的幂的特殊情况,则上式为
T(n)=2T(n2)+n
所以
2T(n2)=4T(n4)+n
4T(n4)=8T(n8)+n

2k1T(n2k1)=2kT(n2k)+n
容易知道起始条件T(1)=1,那么令n2k=1,解得k=log2n
所以T(n)=kn+2kT(n2k)=nlog2n+log2n
所以T(n)=O(nlog2n)
当为一般情况时,可根据主定理的情况2(a=2,b=2,f(n)=n),得出渐进复杂度为O(nlog2n)

原创粉丝点击