算法的基本概念
利用计算机算法为计算机解题的过程实际上是在实施某种算法
- 算法的基本特征
可行性、确定性、有穷性、拥有足够的情报 - 算法的组成要素
一个算法由数据对象和操作以及其控制结构这两部分组成 - 算法的基本运算和操作
算术运算、逻辑运算、关系运算、数据传输 - 算法的基本控制结构
顺序结构、选择结构、循环结构 - 算法基本设计方法
列举法、归纳法、递推、递归、减半递推技术、回溯法
算法的复杂度
判断一个算法好与坏的标准包括时间复杂度与空间复杂度,时间复杂度越小越好,空间复杂度越小越好
算法的工作量用算法所执行的基本运算次数来计算。而算法所执行的基本运算次数是问题规模的函数,即算法的工作量=f(n),其中n是问题的规模。
数据结构的基本概念
- 数据:数据是客观事物的符号表示,是能输入到计算机中并被计算程序识别和处理的符号的总称,如文档、声音、视频等。
- 数据元素:是数据的基本单位
- 数据对象:是性质相同的数据元素的集合,是数据的一个子集
- 数据结构:是指由某一数据对象中所有数据成员之间的关系组成的集合
数据结构研究的 3 个方面
- 数据集合中各数据元素之间所固有的逻辑关系,即数据的逻辑结构;
- 在对数据进行处理时,各数据元素在计算机中的存储关系,即数据的存储结构;
- 对各种数据结构进行的运算。
逻辑结构和存储结构
数据结构可分为逻辑结构和存储结构。
数据的逻辑结构是对数据元素之间的逻辑关系的描述,与数据存储无关,是面向问题的,是独立于计算机的。它有两个要素:一是数据元素的集合,即数据对象,通常记为D;二是D上的关系,即数据对象之间的关系,它反映了数据元素之间的前后件关系,通常记为R。
- B=(D,R)//B表示数据结构
- 例如,如果把一年四季看作一个数据结构,则可表示成:B =(D,R)
D ={春季,夏季,秋季,冬季}
R ={(春季,夏季),(夏季,秋季),(秋季,冬季)}
数据的存储结构也称数据的物理结构,是数据在计算机中的存放的方式,是面向计算机的,它包含数据元素的存储方式和关系的存储方式。
数据结构和逻辑结构的关系: 一种数据的逻辑结构可以表示成多种存储结构即数据的逻辑结构和存储结构不一定一一对应。
常见的存储结构有:顺序、链接、索引等,采用不同的存储结构其数据处理的效率是不同的。
- 顺序存储方式主要用于线性的数据结构,它把逻辑上相邻的数据元素存储在物理上相邻的存储单元里,结点之间的关系由存储单元的邻接关系来体现。
- 链式存储结构就是在每个结点中至少包含一个指针域,用指针来体现数据元素之间逻辑上的联系。
线性结构和非线性结构
根据数据结构中各数据元素之间前后件关系的复杂程度,一般将数据结构分成两大类型:线性结构与非线性结构。
一、
如果一个非空的数据结构满足下列两个条件,则称该数据结构为线性结构。
- 有且只有一个根结点
- 每一个结点最多有一个前件
线性结构又称线性表。在一个线性结构中插入或删除任何一个结点后还应是线性结构。如果一个数据结构不是线性结构,则称之为非线性结构。
栈、队列、串、双向链表等是线性结构;树、图、数组、广义表等都是非线性结构。
空的数据结构是线性结构还是非线性结构:都有可能,根据具体情况来确定。如果对该数据结构的算法是按线性结构的规则处理的,则属于线性结构;否则属于非线性结构。
二、
线性表的顺序存储结构具有以下两个基本特点:
- 线性表中所有元素所占的存储空间是连续的
- 线性表中各数据元素在存储空间中是按逻辑顺序依次存放的
元素 ai 的存储地址为:ADR(ai)=ADR(a1)+(i-1)k,ADR(a1)为第一个元素的地址,k 代表每个元素占的字节数。
三、
顺序表的运算有查找、插入、删除 3种。
栈
栈的基本概念:
栈是一种特殊的线性表,只允许在表的一端进行插入和删除的线性表;插入,删除的一端为栈顶,另一端为栈底;当表中没有元素时为空栈。
栈是按照“先进后出”或“后进先出”的原则组织数据的。
栈的顺序存储及其运算:
用一维数组S(1:m)作为栈的顺序存储空间,其中m为最大容量。
在栈的顺序存储空间S(1:m)中,S(bottom)为栈底元素,S(top)为栈顶元素。
top=0表示栈空;top=m表示栈满。
栈的基本运算有 3 种:入栈、退栈与读栈顶元素。
① 入栈运算:在栈顶位置插入一个新元素;
② 退栈运算:取出栈顶元素并赋给一个指定的变量;
③ 读栈顶元素:将栈顶元素赋给一个指定的变量。
队列
队列的基本概念:
队列是一种特殊的线性表,只允许在表的一端插入,在另一端删除,允许插入的一端是队尾(rear),允许删除的一端为队头(front),当表中没有元素是空队列。
队列的修改是依照先进先出的原则进行的。
队列的运算
- 入队运算是往队列队尾插入一个数据元素;
- 退队运算是从队列的队头删除一个数据元素。
队列的顺序存储结构一般采用队列循环的形式。循环队列 s=0 表示队列空;s=1 且 front=rear 表示队列满。计算循环队列的元素个数:“尾指针减头指针”,若为负数,再加其容量即可。
rear指向的位置是放入元素的位置,front指向的位置是删除元素后的位置
注:判断循环队列元素个数公式(rear-front+容量)%容量,%表示取余数,如果是0说明队列是满的或空的
链表
数据结构中的每一个结点对应于一个存储单元,这种存储单元称为存储结点,简称结点。在链式存储方式中,要求每个结点由两部分组成:
- 一部分用于存放数据元素值,称为数据域;
- 另一部分用于存放指针,称为指针域。其中指针用于指向该结点的前一个或后一个结点(即前件或后件)。
线性链表
线性表的链式存储结构称为线性链表。
在某些应用中,对线性链表中的每个结点设置两个指针,一个称为左指针,用以指向其前件结点;另一个称为右指针,用以指向其后件结点。这样的表称为双向链表。
在线性链表中,各数据元素结点的存储空间可以是不连续的,且各数据元素的存储顺序与逻辑顺序可以不一致,而数据元素之间的逻辑关系是由指针域来确定的。在线性链表中进行插入与删除,不需要移动链表中的元素。
线性单链表中,HEAD 称为头指针,HEAD=NULL(或 0)称为空表。
如果是双向链表的两指针:左指针(Llink)指向前件结点,右指针(Rlink)指向后件结点。
线性链表的基本运算:查找、插入、删除。
带链的栈
栈也是线性表,也可以采用链式存储结构。带链的栈可以用来收集计算机存储空间中所有空闲的存储结点,这种带链的栈称为可利用栈。
树
树(tree)是一种简单的非线性结构。在树结构中,每一个结点只有一个前件,称为父结点,没有前件的结点只有一个,称为树的根结点。
- 结点的度:节点所拥有的子树的个数
- 叶子结点:度为0的结点
- 分支结点:除叶子结点以外的结点
- 结点的层次:根节点在第一层,同一层上左右结点的子结点在下一层
- 树的深度:树的最大层次称为树的深度
- 树的度:所有结点中最大的度称为树的度
二叉树
二叉树是一种很有用的非线性结构,具有以下两个特点:
① 非空二叉树只有一个根结点;
② 每一个结点最多有两棵子树,且分别称为该结点的左子树和右子树。
二叉树的性质
- 在二叉树的第k层上,最多有2k-1(k≥1)个结点
- 深度为m的二叉树最多有2m-1个结点
- 总的结点数 = 度为2的结点数 + 度为1的结点数 + 度为0的结点数
- 在任意一棵二叉树中,度为0的结点(叶子结点)总是比度为2的结点多一个
- 具有 n 个结点的二叉树,其深度至少为[log2n]+1,其中[log2n]表示取 log2n 的整数部分
满二叉树和完全二叉树
满二叉树:除最后一层外,每一层上的所有结点都有两个子结点。在满二叉树中,每一层上的结点数都达到最大值,即在满二叉树的第 k 层上有 2k-1 个结点,且深度为 m 的满二叉树有 2m-1 个结点。
完全二叉树:除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点。
满二叉树也是完全二叉树,二完全二叉树一般不是满二叉树。
- 具有n个结点的完全二叉树的深度为[log2n]+1
- 完全二叉树中度为1的结点数为0或1
二叉树的遍历
在遍历二叉树的过程中,一般先遍历左子树,再遍历右子树。在先左后右的原则下,根据访问根结点的次序,二叉树的遍历分为三类:前序遍历、中序遍历和后序遍历。
- 前序遍历:先访问根结点、然后遍历左子树,最后遍历右子树;并且,在遍历左、右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树。
- 中序遍历:先遍历左子树、然后访问根结点,最后遍历右子树;并且,在遍历左、右子树时,仍然先遍历左子树,然后访问根结点,最后遍历右子树。
- 后序遍历:先遍历左子树、然后遍历右子树,最后访问根结点;并且,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后访问根结点。
在二叉树遍历中,无论是前序遍历,中序遍历还是后序遍历,二叉树叶子结点的先后顺序都是不变的。
查找
顺序查找
顺序查找是从表的一端开始,依次扫描表中的各个元素,并与所要查找的数进行比较。 在下列两种情况下也只能采用顺序查找。
- 如果线性表为无序表,则不管是顺序存储结构还是链式存储结构,只能用顺序查找;
- 即使是有序线性表,如果采用链式存储结构,也只能用顺序查找。
二分查找
二分法查找,也称拆半查找,是一种高效的查找方法。能使用二分法查找的线性表必须满足用顺序存储结构和线性表是有序表两个条件。
对于长度为 n 的有序线性表,在最坏情况下,二分法查找只需比较 log2n 次,而顺序查找需要比较 n 次。
排序
交换排序
冒泡排序法的平均执行时间是O(n2),而快速排序法的平均执行时间是O(nlog2n)。
- 冒泡排序法:在最坏的情况下,冒泡排序需要比较次数为 n(n-1)/2。
- 快速排序法:在最坏的情况下,快速排序需要比较次数为 n(n-1)/2。
插入类排序法
- 简单插入排序法,最坏情况需要 n(n-1)/2 次比较;
- 希尔排序法,最坏情况需要 O(n1.5)次比较。
选择类排序
- 简单选择排序法,最坏情况需要 n(n-1)/2 次比较;
- 堆排序法,最坏情况需要 O(nlog2n)次比较。
相比以上几种(除希尔排序法外),堆排序法的时间复杂度最小。
快速排序法:任取待排序序列中的某个元素作为基准(一般取第一个元素),通过一次排序,将待排元素分为左右两个子序列,左子序列元素的排序码均小于或等于基准元素的排序码,右子序列的排序码则大于基准元素的排序码,然后分别对两个子序列继续进行排序,直至整个序列有序。
快速排序每一次数据元素的移动会产生新的逆序。