数据结构复习

一、考试要求

1、掌握数据结构的基本概念、基本原理和基本方法。

2、掌握数据的逻辑结构、存储结构及基本操作的实现,能够对算法进行基本的时间复杂度与空间复杂度的分析。

3、能够运用数据结构基本原理和方法进行问题的分析与求解,具备采用C或C++语言设计与实现算法的能力。

二、考试内容

写在前面--数据结构在学什么?

  • 如何用程序代码把现实世界的问题信息化
  • 如何用计算机高效地处理这些信息从而创造价值

数据:数据是信息的载体,是描述客观事物属性的数、字符及所有能输入到计算机中并被计算机程序识别和处理的符号的集合。【二进制0和1】数据是计算机程序加工的原料。

数据元素:是数据的基本单位,通常作为一个整体进行考虑和处理。一个数据元素可由若干数据项组成。

数据项:是构成数据元素的不可分割的最小单位。

数据结构是相互之间存在一种或多种特定关系的数据元素的集合。

数据对象是具有相同性质的数据元素的集合,是数据的一个子集。

数据结构的三要素

数据的逻辑结构:数据元素之间的逻辑关系

  • 集合:各元素同属于一个集合,别无其他关系
  • 线性结构:数据元素之前是一对一的关系。除了第一个元素,所有元素都有唯一前驱;除了最后一个元素,所有元素都有唯一后继
  • 树形结构:数据元素之间是一对多的关系
  • 图结构:数据元素之间是多对多的关系

数据的物理结构(存储结构):如何用计算机表示数据元素的逻辑关系-各个数据元素在内存中如何存储

顺序存储:把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现

链式存储:逻辑上相邻的元素在物理位置上可以不相邻,借助指示元素存储地址的指针来表示元素之间的逻辑关系(用指针表示下一个数据元素的存储地址)

索引存储:在存储元素信息的同时,还建立附加的索引表。索引表中的每项称为索引项,索引项的一般形式是(关键字,地址)

散列存储:根据元素的关键字直接计算出该元素的存储地址,又称哈希存储(Hash)

注意:

①若采用顺序存储,则各个数据元素在物理上必须是连续的;若采用非顺序存储,则各个数据元素在物理上可以是离散的

②数据的存储结构会影响存储空间分配的方便程度

③数据的存储结构会影响对数据运算的速度

数据的运算:施加在数据上的原酸包括运算的定义和实现。运算的定义是针对逻辑结构的,指出运算的功能;运算的实现是针对存储结构的,指出运算的具体操作步骤

例:逻辑结构--线性结构(队列)

结合现实需求定义队列这种逻辑结构的运算:

①队头元素出队

②新元素入队

③输出队列长度

数据类型是一个值的集合和定义在此集合上的一组操作的总称

①原子结构。其值不可再分的数据类型

②结构类型。其值可以再分解为若干成分(分量)的数据类型

 bool类型        值的范围:true、false        可进行操作:与或非···

int类型        值的范围:-214783648~214783647        可进行操作:加减乘除模运算

struct Customer{
//号数【定义一个具体的结构类型,表示排队顾客信息。根据具体业务需求来确定值得范围,可进行操作】
        int num; 

//人数【值的范围:num(1~9999)、people(1~12)可进行操作:如拼桌运算,把人数相加合并】
        int people;

        ···//其他必要的信息

};

抽象数据类型(Abstract Data Typ,ADT)是抽象数据组织及相关操作【ADT用数学化的语言定义数据的逻辑结构、定义运算。与具体的实现无关】

算法

程序=数据结构+算法

数据结构 :如何用数据正确地描述现实世界的问题,并存入计算机

算法:如何高效地处理这些数据,以解决实际问题

算法是对特定问题求解步骤的一种描述,它是指令的有限序列,其中的每条指令表示一个或多个操作

要解决的问题:做番茄炒蛋

食材:鸡蛋4个、西红柿2个、料酒少许、盐一勺、糖少许

步骤:

①西红柿切块

②鸡蛋加料酒打匀

③将锅烧热,导入鸡蛋翻炒

④倒入西红柿翻炒

⑤加少许盐、糖

⑥装盘

 

 

 

 

 

 

 

 算法:将该线性表按照年龄递增排序
Step 1:扫描5个元素,找到年龄最小的一个元素,插入到第1个位置
Step 2:扫描剩下的4个元素,找到年龄最小的一个元素,插入到第2个位置

Step 3:扫描剩下的3个元素,找到年龄最小的一个元素,插入到第3个位置

Step 4:扫描剩下的2个元素,找到年龄最小的一个元素,插入到第4个位置

算法的特性【算法必须具备的特性】

  • 有穷性:一个算法必须在执行有穷步之后结束,且每一步都可在有穷时间内完成。        【注:算法必须是有穷的(用有限步骤解决某个特定的问题),而程序可以是无穷的(如微信是程序不是算法)】 
  • 确定性:算法中每条指令必须有确切的含义,对于相同的输入只能得出相同的输出
  • 可行性:算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现
  • 输入:一个算法有零个或多个输入,这些输入取自于某个特定的对象的集合
  • 输出:一个算法有一个或多个输出,这些输出是与输入有着某种特定关系的量

好算法的特质【设计算法时要尽量追求的目标】

  • 正确性:算法应能够正确地解决求解问题
  • 可读性:算法应具有良好的可读性,以帮助人们理解【注:算法可以用代码、伪代码描述,甚至用文字描述,重要的是“无歧义”地描述出解决问题的步骤】
  • 健壮性:输入非法数据时,算法能适当地做出反应或进行处理,而不会莫名其妙的输出结果
  • 高效率与低存储量需求:画的时间少,时间复杂度低;不费内存,空间复杂度低

算法效率的度量 :时间复杂度,空间复杂度

如何评估算法时间开销?让算法先运行,事后统计运行时间?

存在什么问题?

  • 和机器性能有关,如:超级计算机 v.s. 单片机
  • 和编程语言有关,越高级的语言执行效率越低
  • 和编译程序产生的机器指令质量有关【能否排除与算法本身无关的外界因素】
  • 有些算法是不能事后再统计的,如:导弹控制算法【能否事先估计】

 算法时间复杂度:事前预估算法时间开销T(n)与问题规模 n 的关系(T 表示 “time”)

  • 最坏时间复杂度:最坏情况下算法的时间复杂度
  • 平均时间复杂度:所有输入示例等概率出现的情况下,算法的期望运行时间
  • 最好时间复杂度:最好情况下算法的时间复杂度

时间复杂度--时间开销与问题规模n之间的关系

空间复杂度--空间开销(内存开销)与问题规模n之间的关系--程序运行时的内存需求

一、线性表

(一) 线性表的定义和基本操作

【注:数据结构三要素--逻辑结构、数据的运算、存储结构(物理结构),存储结构不同,运算的实现方式不同】

线性表的定义--数据结构三要素--逻辑结构

线性表是具有相同数据类型【每个数据元素所占空间一样大】的n(n>=0)个数据元素的有限序列【有次序】,其中n为表长,当n=0是线性表是一个空表。若用L命名线性表,则其一般表示为  L = (a1, a2, … , ai, ai+1, … , an)

几个概念:
ai 是线性表中的“第i个”元素线性表中的位序【注意:位序从1开始数组下标从0开始】

a1是表头元素;an 是表尾元素。

除第一个元素外,每个元素有且仅有一个直接前驱;除最后一个元素外,每个元素有且仅
有一个直接后继

线性表--Linear List

线性表的基本操作--数据结构三要素--运算 

为什么要实现对数据结构的基本操作?

①团队合作编程,你定义的数据结构要让别人能够很方便的使用(封装)

②将常用的操作/运算封装成函数,避免重复工作,降低出错风险

线性表的基本操作

InitList(&L):初始化表。构造一个空的线性表L,分配内存空间【从无到有】

DestroyList(&L):销毁操作。销毁线性表,并释放线性表L所占用的内存空间【从有到无】

ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。【增】

ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。【删】

LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素。

GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值。【改、查(“改”之前也要“查”)】

其他常用操作:
Length(L):求表长。返回线性表L的长度,即L中数据元素的个数。
PrintList(L):输出操作。按前后顺序输出线性表L的所有元素值。
Empty(L):判空操作。若L为空表,则返回true,否则返回false。

Tips:
①对数据的操作(记忆思路) —— 创销、增删改查
②C语言函数的定义 —— <返回值类型> 函数名 (<参数1类型> 参数1,<参数2类型> 参数2,……)
③实际开发中,可根据实际需求定义其他的基本操作
④函数名和参数的形式、命名都可改变【Key:命名要有可读性】
⑤什么时候要传入引用“&” —— 对参数的修改结果需要“带回来”

 

(二) 线性表的实现

1、顺序存储

顺序表的定义

线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列【每个数据元素所占空间一样大】

线性表L的逻辑结构

顺序表--用顺序存储的方式实现线性表顺序存储。把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现

顺序表的实现--静态分配

#define MaxSize 10 //定义最大长度
typedef struct{
ElemType data[MaxSize]; //用静态的“数组”存放数据元素
int length; //顺序表的当前长度
}SqList; //顺序表的类型定义

 

给各个数据元素分配连续的存储空间,大小为MaxSize*sizeof(ElemType)

 

 

Q:如果“数组”存满了怎么办?

 A:可以放弃治疗,顺序表的表长刚开始确定后就无法更改(存储空间是静态的)

思考:如果刚开始就声明一个很大的内存空间呢?存在什么问题?【可能会浪费吧】

顺序表的实现--动态分配

#define InitSize 10     //顺序表的初始长度
typedef struct{
    ElemType *data;     //指示动态分配数组的指针
    int MaxSize;         //顺序表的最大容量
    int length;         //顺序表的当前长度
} SeqList;             //顺序表的类型定义(动态分配方式)

 

顺序表的特点:

①随机访问,即可以再O(1)时间内找到第1个元素【代码实现:data[i-1];静态动态一样】

②存储密度高,每个节点只存储数据元素

③扩展容量不方便(即便采用动态分配的方式实现,拓展长度的时间复杂度也比较高)

④插入、删除操作不方便 ,需要移动大量元素

 

顺序表插入删除
顺序表查找

顺序表的基本操作

  • 按位查找-- 代码实现、时间复杂度分析
  • 按值查找--代码实现、时间复杂度分析

一、考试要求

二、考试内容

写在前面--数据结构在学什么?2

算法

算法效率的度量 :时间复杂度,空间复杂度

一、线性表

(一) 线性表的定义和基本操作

(二) 线性表的实现

1、顺序存储

顺序表插入删除

顺序表查找

2、链式存储

3、线性表的应用

二、栈、队列和数组

(一) 栈和队列的基本概念

(二) 栈和队列的顺序存储结构

(三) 栈和队列的链式存储结构

(四) 栈和队列的应用

(五) 特殊矩阵的压缩存储

三、树与二叉树

(一) 树的基本概念

(二) 二叉树

1、二叉树的定义及其主要特征

2、二叉树的顺序存储结构和链式存储结构

3、二叉树的遍历

4、线索二叉树的基本概念和构造

(三) 树、森林

1、树的存储结构

2、森林与二叉树的转换

3、树和森林的遍历

(四) 树与二叉树的应用

1、二叉排序树

2、平衡二叉树

3、哈夫曼(Huffman) 树和哈夫曼编码

四、图

(一) 图的基本概念

(二) 图的存储及基本操作

1、邻接矩阵法

2、邻接表法

3、邻接多重表、十字链表

(三) 图的遍历

1、深度优先搜索

2、广度优先搜索

(四) 图的基本应用

1、最小(代价) 生成树

2、最短路径

3、拓扑排序

4、关键路径

五、查找

(一) 查找的基本概念

(二) 顺序查找法

(三) 分块查找法

(四) 折半查找法

(五) B-树及其基本操作、B+树的基本概念

(六) 散列(Hash) 表

(七) 字符串模式匹配

(八) 查找算法的分析及应用

六、排序

(一) 排序的基本概念

(二) 插入排序

1、直接插入排序

2、折半插入排序

(三) 冒泡排序(Bubble Sort)

(四) 简单选择排序

(五) 希尔排序(Shell Sort)

(六) 快速排序

(七) 堆排序

(八) 二路归并排序(Merge Sort)

(九) 基数排序

(十) 各种排序算法的比较

(十一) 排序算法的应用

三、试卷结构(题型分值)

四、参考书目


2、链式存储
3、线性表的应用

广义表

例、广义表LS=(a,(b),((c,(d)))) 求:表头、表尾、长度、深度

表头:a【第一个逗号前】

表尾:((b),((c,(d))))【第一个逗号后的所有内容外再加一个括号】

长度:3【逗号分隔开几个】a       (b)         ((c,(d)))

深度:4【最多层括号】

例、画出广义表LS=(( ),(e),(a,(b,s,d)))的头尾链表存储结构

求存储地址

例、数组元素a[0...2][0...3]的首地址为2000,元素长度为4,求LOC[1,2]。

首地址2000        i--1   j--2   n---这一行多少元素【0---3】--n=4,k=4长度

代码设计

1.设单链表的结点的结构为ListNode=(data,link),阅读下面的函数,指出它所实现的功能。

int unknow(ListNose *Ha)
{    int n=0;
    LinkNode *p=Ha->link;
    while(p)
    {
        n++;
        p=p->next;
    }
    return(n);
}
//计算单链表的长度

2.对于顺序表L指出以下算法的功能。

void fun(SqList*&L)
{    
    int i,j=0;
    for(i=1;i<L->length;i++)
    if(L->data[i] > L->data[j])
    j=i;
    for(i=j;i<L->length-1;i++)
    L->data[i]=L->data[i+1];
    L->length--;
}
//找最大值位置并且把最大值删除

3.假设二叉树采用二叉链存储结构存储,设计一个递归算法,计算一棵给定二叉树的所有结点个数。

int NodeCount(BTNode *b)
{
    if(b==NULL)
        return 0;
    else
        return NodeCount(b->child)+NodeCount(b->rchild)+1;
}

4.求二叉树高度的算法(递归)

int BTHeight(BTNode *b)
{
    int lchild,rchild;
    if(b==NULLii)
        return 0;
    else{
        lchild=BTHeight(b->lchild);
        rchild=BTHeight(b->rchild);
        return(lchild>rchild)?(lchild+1);(rchild+1);
        }
}

5.编写在一有序顺序表中插入数据元素X的算法INSERT(L,X)

void INSERT(SqList &L,ElemType X){
    int i=0;
    if(L.data[0]<L.data[1]{
        while(x<L.data[i]&&i<=L.length-1)
            ++i;
    }
    else{
        while(x>L.data[i]&&i<=L.length-1)
            ++i;
        }
    for(int j=L.length-1;j>=i;j--)
    L.data[j+1]=data[j];
    L.data[i]=x;
    L.length++;
}
//最终版本不知道应该是下面这个
void INSERT(SqList &L,ElemType X){
    int i=0;
    
    while(x<L.data[i]&&i<=L.length-1)
        ++i;//以上找到插入位置
    for(int j=L.length-1;j>=i;j--)
    L.data[j+1]=data[j];
    L.data[i]=x;
    L.length++;//元素后移插入元素后长度加一
}

6.假设二叉树采用二叉链存储结构,设计一个递归算法,输出给定二叉树的所有叶子结点。

void DispLeaf(BTNode *b){
    if(b!=NULL){
        if(b->lchild==NULL&&b->rchild==NULL)
            printf("%c",b->data);
            DispLeaf(b->lchild);
            DispLeaf(b->rchild);
    }
}

二、栈、队列和数组

(一) 栈和队列的基本概念

(二) 栈和队列的顺序存储结构

(三) 栈和队列的链式存储结构

(四) 栈和队列的应用

(五) 特殊矩阵的压缩存储

三、树与二叉树

(一) 树的基本概念

(二) 二叉树

1、二叉树的定义及其主要特征
2、二叉树的顺序存储结构和链式存储结构
3、二叉树的遍历
4、线索二叉树的基本概念和构造

例1、已知一棵二叉树的后序遍历和中序遍历的序列分别为:ACDBGIHFE和ABCDEFGHI。

后序遍历的最后一个字母为根E

中序遍历的E根位置的左为左子树、右为右子树

后序-左右根--可知E为根

中序-左根右--将E带入后序中可知ABCD为左子树元素/FGHI为右子树元素

将左子树ABCD带入后序中可知后序中顺序ACDB可知B为左子树的根

再B带入中序顺序ABCD可知A为B的左子树,CD为B的右子树

将CD带入后序顺序CD可知D为C的根

将C带入中序顺序CD可知C为D的左子树

左子树完成

将FGHI带入后序顺序GIHF可知F为右子树根

将GIH带入中序顺序GHI可知GHI为F的右子树

将GHI带入后序顺序GIH可知H为根

将GI带入中序顺序GHI可知G为H的左子树,I为H的右子树

例2、已知一棵二叉树的前序遍历和中序遍历的序列分别为:ABDGHCEFI和GDHBAECIF。并在该二叉树上建立中序线索。

前序遍历的第一个字母为根E

中序遍历的E根位置的左边结点为左子树、右为右子树

建立中序线索:

先根据二叉树写出中序序列--左跟根右

从第一元素G开始

G没有左右子树--因为是第一个元素前面没有前驱--画出虚线指向后继D

H没有左右子树--画出虚线指向前驱结点D--画出虚线只想后继结点B

D有左右子树无需再画

B有左子树没有左子树--画出虚线指向后继结点A

A有左右子树无需再画

C有左右子树无需再画

E没有左右子树--画出虚线指向前驱结点A--画出虚线指向后继结点C

I没有左右子树--画出虚线指向前驱结点C--画出虚线指向后继结点F

F有左子树没有右子树--因为是最后一个结点没有后继结点所以无需再画

例3、先序遍历次序:abcdefg        中序遍历:badfegc

求叶子结点个数

例、已知一棵度为3的树中,有度数为3的结点100个,度数为2的结点200个,求叶子结点的个数,并给出推导过程。

 N=N0+N1+N2+N3【结点总数=度为1结点个数+度为2个数+度为3个数】

N-1=0*N0+1*N1+2*N2+3*N3【结点总数-1=度×对应度的个数】

(三) 树、森林

1、树的存储结构
2、森林与二叉树的转换
3、树和森林的遍历

(四) 树与二叉树的应用

1、二叉排序树

建立二叉排序树

例、对于给定结点的关键字集合K={34,76,45,18,26,54,92,38}

(1)试构造一棵二叉排序树

将序列第一个34当做根

左小右大

76>34则76为34的右子树

45>34则属于右子树--45<76则45为76的左子树

18<34则为34左子树

26<34则属于左子树--26>18则为18的右子树

54>34则属于右子树--54<76属于76的左子树--54>45则为45的右子树

92>34则属于右子树--92>76则为76的右子树

38>34则属于右子树--38<76则属于左子树--38<45则为45的左子树

(2)查找54需要比较几次?查找100的比较次数?

查找54即看54在第几层

100>34则在其右子树--此为查找一次

100>76则在其右子树--此为查找第二次

100>92则在其右子树--此为查找第三次--但是92已经无后继元素则查找失败到此共查找3次

【100不在上述二叉树中】

(3)求等概率情况下查找成功的平均查找长度ASI。

成功--层数从1开始共4层

ASI成功=(第一层1*第一层节点个数+第二层2*第二层个数+····)÷结点总数

ASI失败层数从0开始,每层×的数是缺少的叶节点数,÷的个数是缺少的叶结点的总数【蓝色】

2、平衡二叉树
3、哈夫曼(Huffman) 树和哈夫曼编码

哈夫曼树

例、假设用于通信的电文仅由A,B,C,D,E,F,G 8个字母组成,字母在电文中出现的频率分别为7,19,2,6,32,3,21,10,试为这8个字母设计哈夫曼树及哈弗曼编码。

哈弗曼编码:

最小生成树

 例、对于下图所示的带权无向图,给出利用普利姆算法(从定点开始构造)和克鲁斯卡尔算法构造出的最小生成树,并按求解的顺序给出最小生成树的所有边,每条边用(i,j)表示。

注意:不要形成环路

普利姆:每次与下一步相加最小?

克鲁斯:每一步最小

四、图

(一) 图的基本概念

(二) 图的存储及基本操作

1、邻接矩阵法
2、邻接表法
3、邻接多重表、十字链表

(三) 图的遍历

1、深度优先搜索
2、广度优先搜索

(四) 图的基本应用

1、最小(代价) 生成树
2、最短路径
3、拓扑排序
4、关键路径
五、查找

(一) 查找的基本概念

(二) 顺序查找法

(三) 分块查找法

(四) 折半查找法

(五) B-树及其基本操作、B+树的基本概念

(六) 散列(Hash) 表

(七) 字符串模式匹配

例1:、给出字符串“abacacaaad”在KMP算法中的next和nextval数组。

下标0123456789
关键字abacacaaad
Next-1001010111
Nextval-10-11-11-1111

蓝色部分为固定套路

首先看第三行next:

012
aba
-10?=0

第三个即下标为2的a的前面的b (不要看到第一个数)之前有多少个与b相等,有几个就填几个

那么b之前只有一个a显然两者不相等则?=0填0

0123
abac
-100?=1

同样的方法:

看c之前的a与第一个元素即下标为0的元素a相等则有1

再看c之前最近的除了第一个元素外组成的两个元素ba与从第一个开始往后组成的ab不相等有0

最终:?=1+0=1

01234
abaca
-1001?=0

4-a之前的

①c与前面元素(从第一元素开始往后组成的)没有相等的--0

②ac与前面元素(即不等于ab)没有相等的--0

③bac与前面元素(即不等于aba)没有相等的--0

最终?=0+0+0=0 

012345
abacac
-10010?=1

5-c之前的元素:

①4-a与0-a相等---1

②34-ca与01-ab不相等---0

③234-aca与012- aba不相等--0

④1234-baca与0123-abac不相等--0

最终?=1+0+0+0=1

第四行nextval

下标01
关键字ab
Next-10
Nextval-1?=0

1-b对应的next=0根据这个0去找下标为0的关键字是0-a而a≠b则nextval=b-next=0

下标012
关键字aba
Next-100
Nextval-10?=-1

2-a对应的next=0找到下标0-a而a=a则2-a-nextval=0-a-nextval=-1

下标0123
关键字abac
Next-1001
Nextval-10-1?=1

根据3-c-next=1去找到下标为1的1-b而b≠c则c-nextval=c-next=1

``````

(八) 查找算法的分析及应用

六、排序

(一) 排序的基本概念

(二) 插入排序

1、直接插入排序
2、折半插入排序

(三) 冒泡排序(Bubble Sort)

(四) 简单选择排序

(五) 希尔排序(Shell Sort)

(六) 快速排序

(七) 堆排序

(八) 二路归并排序(Merge Sort)

(九) 基数排序

(十) 各种排序算法的比较

(十一) 排序算法的应用

三、试卷结构(题型分值)

1. 本科目满分为150分,考试时间为180分钟。

2.题型结构

(1)选择题:占总分的40/150。

(2)简答题: 占总分的20/150。

(3)分析计算题:占总分的30/150。

(4)算法分析阅读题: 占总分的30/150。

(5)算法设计题:占总分的30/150。

四、参考书目

《数据结构(C语言版)》,严蔚敏、吴伟民编著,清华大学出版社,2007年。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值