当前位置:首页 » 操作系统 » 堆删除算法

堆删除算法

发布时间: 2023-03-16 20:47:10

㈠ dijkstra算法是什么

迪杰斯特拉算法用来解决从顶点v0出发到其余顶点的最短路径,该算法按照最短路径长度递增的顺序产生所以最短路径。

对于图G=(V,E),将图中的顶点分成两组:第一组S:已求出的最短路径的终点集合(开始为{v0})。第二组V-S:尚未求出最短路径的终点集合(开始为V-{v0}的全部结点)。

堆优化

思考

该算法复杂度为n^2,我们可以发现,如果边数远小于n^2,对此可以考虑用堆这种数据结构进行优化,取出最短路径的复杂度降为O(1);每次调整的复杂度降为O(elogn);e为该点的边数,所以复杂度降为O((m+n)logn)。

实现

1、将源点加入堆,并调整堆。

2、选出堆顶元素u(即代价最小的元素),从堆中删除,并对堆进行调整。

3、处理与u相邻的,未被访问过的,满足三角不等式的顶点

1):若该点在堆里,更新距离,并调整该元素在堆中的位置。

2):若该点不在堆里,加入堆,更新堆。

4、若取到的u为终点,结束算法;否则重复步骤2、3。

㈡ 数据结构考试重点

第一章 数据结构基本概念
1、基本概念:理解什么是数据、数据对象、数据元素、数据结构、数据的逻辑结构与物理结构、逻辑结构与物理结构间的关系。
2、面向对象概念:理解什么是数据类型、抽象数据类型、数据抽象和信息隐蔽原则。了解什么是面向对象。由于目前关于这个问题有许多说法,我们采用了一种最流行的说法,即Coad与Yourdon 给出的定义:面向对象 = 对象 + 类 + 继承 + 通信。
要点:
·抽象数据类型的封装性
·面向对象系统结构的稳定性
·面向对象方法着眼点在于应用问题所涉及的对象
3、数据结构的抽象层次:理解用对象类表示的各种数据结构
4、算法与算法分析:理解算法的定义、算法的特性、算法的时间代价、算法的空间代价。
要点:·算法与程序的不同之处需要从算法的特性来解释
·算法的正确性是最主要的要求
·算法的可读性是必须考虑的
·程序的程序步数的计算与算法的事前估计
·程序的时间代价是指算法的渐进时间复杂性度量

第二章 数组
1、作为抽象数据类型的数组:数组的定义、数组的按行顺序存储与按列顺序存储
要点:
·数组元素的存放地址计算
2、顺序表:顺序表的定义、搜索、插入与删除
要点:
·顺序表搜索算法、平均比较次数的计算
·插入与删除算法、平均移动次数的计算
3、多项式:多项式的定义
4、字符串:字符串的定义及其操作的实现
要点:
·串重载操作的定义与实现

第三章 链接表
1、单链表:单链表定义、相应操作的实现、单链表的游标类。
要点:
·单链表的两种定义方式(复合方式与嵌套方式)
·单链表的搜索算法与插入、删除算法
·单链表的递归与迭代算法
2、循环链表:单链表与循环链表的异同
3、双向链表:双向链表的搜索、插入与删除算法、链表带表头结点的优点
4、多项式的链接表示

第四章 栈与队列
1、栈:栈的特性、栈的基本运算
要点:
·栈的数组实现、栈的链表实现
·栈满及栈空条件、抽象数据类型中的先决条件与后置条件
2、栈的应用:用后缀表示计算表达式,中缀表示改后缀表示
3、队列:队列的特性、队列的基本运算
要点:
·队列的数组实现:循环队列中队头与队尾指针的表示,队满及队空条件
·队列的链表实现:链式队列中的队头与队尾指针的表示、
4、双向队列:双向队列的插入与删除算法
5、优先级队列:优先级队列的插入与删除算法

第五章 递归与广义表
1、递归:递归的定义、递归的数据结构、递归问题用递归过程求解
要点:·链表是递归的数据结构,可用递归过程求解有关链表的问题
2、递归实现时栈的应用
要点:·递归的分层(树形)表示:递归树
·递归深度(递归树的深度)与递归工作栈的关系
·单向递归与尾递归的迭代实现
3、广义表:广义表定义、广义表长度、广义表深度、广义表表头、广义表表尾
要点:
·用图形表示广义表的存储结构
·广义表的递归算法

第六章 树与森林
1、树:树的定义、树的基本运算
要点:
·树的分层定义是递归的
·树中结点个数与高度的关系
2、二叉树:二叉树定义、二叉树的基本运算
要点:
·二叉树性质、二叉树中结点个数与高度的关系、不同种类的二叉树棵数
·完全二叉树的顺序存储、完全二叉树的双亲、子女和兄弟的位置
·二叉树的前序·中序·后序·层次遍历
·前序
·中序
·后序的线索化二叉树、前驱与后继的查找方法
3、霍夫曼树:霍夫曼树的构造方法、霍夫曼编码、带权路径长度的计算
4、树的存储:树的广义表表示、树的双亲表示、树与二叉树的对应关系、树的先根·中根·后根·层次遍历。
5、堆:堆的定义、堆的插入与删除算法
要点:
·形成堆时用到的向下调整算法及形成堆时比较次数的上界估计
·堆插入时用到的向上调整算法

第七章 集合与搜索
1、集合的概念:集合的基本运算、集合的存储表示
要点:
·用位数组表示集合时集合基本运算的实现
·用有序链表表示集合时集合基本运算的实现
2、并查集:并查集定义、并查集的三种基本运算的实现
3、基本搜索方法
要点:
·对一般表的顺序搜索算法(包括有监视哨和没有监视哨)
·对有序顺序表的顺序搜索算法、用判定树(即扩充二叉搜索树)描述搜索,以及平均搜索长度(成功与不成功)的计算。
·对有序顺序表的折半搜索算法、用判定树(即扩充二叉搜索树)描述搜索,以及平均搜索长度(成功与不成功)的计算。
4、二叉搜索树:
要点:
·动态搜索树与静态搜索树的特性
·二叉搜索树的定义、二叉搜索树上的搜索算法、二叉搜索树搜索时的平均搜索长度(成功与不成功)的计算。
·AVL树结点上的平衡因子、AVL树的平衡旋转方法
·高度为h的AVL树上的最少结点个数与最多结点个数
· AVL树的搜索方法、插入与删除方法

第八章 图
1、图:图的定义与图的存储表示
要点:
·邻接矩阵表示(通常是稀疏矩阵)
·邻接表与逆邻接表表示
·邻接多重表(十字链表)表示
2、深度优先遍历与广度优先遍历
要点:
·生成树与生成树林的定义
·深度优先搜索是个递归的过程,而广度优先搜索是个非递归的过程
·为防止重复访问已经访问过的顶点,需要设置一个访问标志数组visited
3、图的连通性
要点:
·深度优先搜索可以遍历一个连通分量上的所有顶点
·对非连通图进行遍历,可以建立一个生成森林
·对强连通图进行遍历,可能建立一个生成森林
·关节点的计算和以最少的边构成重连通图
4、最小生成树
要点:
·对于连通网络、可用不会构成环路的权值最小的n-1条边构成最小生成树
·会画出用Kruskal算法及Prim算法构造最小生成树的过程
5、单源最短路径
要点:
·采用逐步求解的方式求某一顶点到其他顶点的最短路径
·要求每条边的权值必须大于零
6、活动网络
要点:
·拓扑排序、关键路径、关键活动、AOE网
·拓扑排序将一个偏序图转化为一个全序图。
·为实现拓扑排序,要建立一个栈,将所有入度为零的顶点进栈
·关键路径的计算

第九章 排序
1、基本概念:关键码、初始关键码排列、关键码比较次数、数据移动次数、稳定性、附加存储、内部排序、外部排序
2、插入排序:
要点:
·当待排序的关键码序列已经基本有序时,用直接插入排序最快
3、选择排序:
要点:
·用直接选择排序在一个待排序区间中选出最小的数据时,与区间第一个数据对调,而不是顺次后移。这导致方法不稳定。
·当在n个数据(n很大)中选出最小的5 ~ 8个数据时,锦标赛排序最快
·锦标赛排序的算法中将待排序的数据个数n补足到2的k次幂2k-1<n≤2k
·在堆排序中将待排序的数据组织成完全二叉树的顺序存储。
4、交换排序:
要点:
·快速排序是一个递归的排序方法
·当待排序关键码序列已经基本有序时,快速排序显着变慢。
5、二路归并排序:
要点:
·归并排序可以递归执行
·归并排序需要较多的附加存储。可以采用一种"推拉法"(参见教科书上习题)实现归并排序,算法的时间复杂度为O (n)、空间复杂度为O(1)
·归并排序对待排序关键码的初始排列不敏感,排序速度较稳定
6、外排序
要点:
·多路平衡归并排序的过程、I/O缓冲区个数的配置
·外排序的时间分析、利用败者树进行多路平衡归并
·利用置换选择方法生成不等长的初始归并段
·最佳归并树的构造及WPL的计算

第十章 索引与散列
1、线性索引:
要点:
·密集索引、稀疏索引、索引表计算
·基于属性查找建立倒排索引、单元式倒排表
2、动态搜索树
要点:
·平衡的m路搜索树的定义、搜索算法
·B树的定义、B树与平衡的m路搜索树的关系
·B树的插入(包括结点分裂)、删除(包括结点调整与合并)方法
·B树中结点个数与高度的关系
·B+树的定义、搜索、插入与删除的方法
3、散列表
要点:
·散列函数的比较
·装填因子 a 与平均搜索长度的关系,平均搜索长度与表长m及表中已有数据对象个数n的关系
·解决地址冲突的(闭散列)线性探查法的运用,平均探查次数的计算
·线性探查法的删除问题、散列表类的设计中必须为各地址设置三个状态
·线性探查法中的聚集问题
·解决地址冲突的(闭散列)双散列法的运用,平均探查次数的计算
·双散列法中再散列函数的设计要求与表长m互质,为此m设计为质数较宜
·解决地址冲突的(闭散列)二次散列法的运用,平均探查次数的计算
·注意:二次散列法中装填因子 a 与表长m的设置
·解决地址冲突的(开散列)链地址法的运用,平均探查次数的计算

㈢ 数据结构题、大哥大姐帮我做下题吧。万分感谢啊

什么是数据、数据对象、数据元素、数据结构、数据的逻辑结构与物理结构、逻辑结构与物理结构间的关系。
2、面向对象概念:理解什么是数据类型、抽象数据类型、数据抽象和信息隐蔽原则。了解什么是面向对象。由于目前关于这个问题有许多说法,我们采用了一种最流行的说法,即Coad与Yourdon 给出的定义:面向对象 = 对象 + 类 + 继承 + 通信。
要点:
·抽象数据类型的封装性
·面向对象系统结构的稳定性
·面向对象方法着眼点在于应用问题所涉及的对象
3、数据结构的抽象层次:理解用对象类表示的各种数据结构
4、算法与算法分析:理解算法的定义、算法的特性、算法的时间代价、算法的空间代价。
要点:·算法与程序的不同之处需要从算法的特性来解释
·算法的正确性是最主要的要求
·算法的可读性是必须考虑的
·程序的程序步数的计算与算法的事前估计
·程序的时间代价是指算法的渐进时间复杂性度量

第二章 数组
1、作为抽象数据类型的数组:数组的定义、数组的按行顺序存储与按列顺序存储
要点:
·数组元素的存放地址计算
2、顺序表:顺序表的定义、搜索、插入与删除
要点:
·顺序表搜索算法、平均比较次数的计算
·插入与删除算法、平均移动次数的计算
3、多项式:多项式的定义
4、字符串:字符串的定义及其操作的实现
要点:
·串重载操作的定义与实现

第三章 链接表
1、单链表:单链表定义、相应操作的实现、单链表的游标类。
要点:
·单链表的两种定义方式(复合方式与嵌套方式)
·单链表的搜索算法与插入、删除算法
·单链表的递归与迭代算法
2、循环链表:单链表与循环链表的异同
3、双向链表:双向链表的搜索、插入与删除算法、链表带表头结点的优点
4、多项式的链接表示

第四章 栈与队列
1、栈:栈的特性、栈的基本运算
要点:
·栈的数组实现、栈的链表实现
·栈满及栈空条件、抽象数据类型中的先决条件与后置条件
2、栈的应用:用后缀表示计算表达式,中缀表示改后缀表示
3、队列:队列的特性、队列的基本运算
要点:
·队列的数组实现:循环队列中队头与队尾指针的表示,队满及队空条件
·队列的链表实现:链式队列中的队头与队尾指针的表示、
4、双向队列:双向队列的插入与删除算法
5、优先级队列:优先级队列的插入与删除算法

第五章 递归与广义表
1、递归:递归的定义、递归的数据结构、递归问题用递归过程求解
要点:·链表是递归的数据结构,可用递归过程求解有关链表的问题
2、递归实现时栈的应用
要点:·递归的分层(树形)表示:递归树
·递归深度(递归树的深度)与递归工作栈的关系
·单向递归与尾递归的迭代实现
3、广义表:广义表定义、广义表长度、广义表深度、广义表表头、广义表表尾
要点:
·用图形表示广义表的存储结构
·广义表的递归算法

第六章 树与森林
1、树:树的定义、树的基本运算
要点:
·树的分层定义是递归的
·树中结点个数与高度的关系
2、二叉树:二叉树定义、二叉树的基本运算
要点:
·二叉树性质、二叉树中结点个数与高度的关系、不同种类的二叉树棵数
·完全二叉树的顺序存储、完全二叉树的双亲、子女和兄弟的位置
·二叉树的前序·中序·后序·层次遍历
·前序
·中序
·后序的线索化二叉树、前驱与后继的查找方法
3、霍夫曼树:霍夫曼树的构造方法、霍夫曼编码、带权路径长度的计算
4、树的存储:树的广义表表示、树的双亲表示、树与二叉树的对应关系、树的先根·中根·后根·层次遍历。
5、堆:堆的定义、堆的插入与删除算法
要点:
·形成堆时用到的向下调整算法及形成堆时比较次数的上界估计
·堆插入时用到的向上调整算法

第七章 集合与搜索
1、集合的概念:集合的基本运算、集合的存储表示
要点:
·用位数组表示集合时集合基本运算的实现
·用有序链表表示集合时集合基本运算的实现
2、并查集:并查集定义、并查集的三种基本运算的实现
3、基本搜索方法
要点:
·对一般表的顺序搜索算法(包括有监视哨和没有监视哨)
·对有序顺序表的顺序搜索算法、用判定树(即扩充二叉搜索树)描述搜索,以及平均搜索长度(成功与不成功)的计算。
·对有序顺序表的折半搜索算法、用判定树(即扩充二叉搜索树)描述搜索,以及平均搜索长度(成功与不成功)的计算。
4、二叉搜索树:
要点:
·动态搜索树与静态搜索树的特性
·二叉搜索树的定义、二叉搜索树上的搜索算法、二叉搜索树搜索时的平均搜索长度(成功与不成功)的计算。
·AVL树结点上的平衡因子、AVL树的平衡旋转方法
·高度为h的AVL树上的最少结点个数与最多结点个数
· AVL树的搜索方法、插入与删除方法

第八章 图
1、图:图的定义与图的存储表示
要点:
·邻接矩阵表示(通常是稀疏矩阵)
·邻接表与逆邻接表表示
·邻接多重表(十字链表)表示
2、深度优先遍历与广度优先遍历
要点:
·生成树与生成树林的定义
·深度优先搜索是个递归的过程,而广度优先搜索是个非递归的过程
·为防止重复访问已经访问过的顶点,需要设置一个访问标志数组visited
3、图的连通性
要点:
·深度优先搜索可以遍历一个连通分量上的所有顶点
·对非连通图进行遍历,可以建立一个生成森林
·对强连通图进行遍历,可能建立一个生成森林
·关节点的计算和以最少的边构成重连通图
4、最小生成树
要点:
·对于连通网络、可用不会构成环路的权值最小的n-1条边构成最小生成树
·会画出用Kruskal算法及Prim算法构造最小生成树的过程
5、单源最短路径
要点:
·采用逐步求解的方式求某一顶点到其他顶点的最短路径
·要求每条边的权值必须大于零
6、活动网络
要点:
·拓扑排序、关键路径、关键活动、AOE网
·拓扑排序将一个偏序图转化为一个全序图。
·为实现拓扑排序,要建立一个栈,将所有入度为零的顶点进栈
·关键路径的计算

第九章 排序
1、基本概念:关键码、初始关键码排列、关键码比较次数、数据移动次数、稳定性、附加存储、内部排序、外部排序
2、插入排序:
要点:
·当待排序的关键码序列已经基本有序时,用直接插入排序最快
3、选择排序:
要点:
·用直接选择排序在一个待排序区间中选出最小的数据时,与区间第一个数据对调,而不是顺次后移。这导致方法不稳定。
·当在n个数据(n很大)中选出最小的5 ~ 8个数据时,锦标赛排序最快
·锦标赛排序的算法中将待排序的数据个数n补足到2的k次幂2k-1<n≤2k
·在堆排序中将待排序的数据组织成完全二叉树的顺序存储。
4、交换排序:
要点:
·快速排序是一个递归的排序方法
·当待排序关键码序列已经基本有序时,快速排序显着变慢。
5、二路归并排序:
要点:
·归并排序可以递归执行
·归并排序需要较多的附加存储。可以采用一种"推拉法"(参见教科书上习题)实现归并排序,算法的时间复杂度为O (n)、空间复杂度为O(1)
·归并排序对待排序关键码的初始排列不敏感,排序速度较稳定
6、外排序
要点:
·多路平衡归并排序的过程、I/O缓冲区个数的配置
·外排序的时间分析、利用败者树进行多路平衡归并
·利用置换选择方法生成不等长的初始归并段
·最佳归并树的构造及WPL的计算

第十章 索引与散列
1、线性索引:
要点:
·密集索引、稀疏索引、索引表计算
·基于属性查找建立倒排索引、单元式倒排表
2、动态搜索树
要点:
·平衡的m路搜索树的定义、搜索算法
·B树的定义、B树与平衡的m路搜索树的关系
·B树的插入(包括结点分裂)、删除(包括结点调整与合并)方法
·B树中结点个数与高度的关系
·B+树的定义、搜索、插入与删除的方法
3、散列表
要点:
·散列函数的比较
·装填因子 a 与平均搜索长度的关系,平均搜索长度与表长m及表中已有数据对象个数n的关系
·解决地址冲突的(闭散列)线性探查法的运用,平均探查次数的计算
·线性探查法的删除问题、散列表类的设计中必须为各地址设置三个状态
·线性探查法中的聚集问题
·解决地址冲突的(闭散列)双散列法的运用,平均探查次数的计算
·双散列法中再散列函数的设计要求与表长m互质,为此m设计为质数较宜
·解决地址冲突的(闭散列)二次散列法的运用,平均探查次数的计算
·注意:二次散列法中装填因子 a 与表长m的设置
·解决地址冲突的(开散列)链地址法的运用,平均探查次数的计算

㈣ 求数据结构试题…重点

这是我们老师要求的重点,即考点。打印出来,背一下就行了,准过!
第一章:绪论
1.1:数据结构课程的任务是:讨论数据的各种逻辑结构、在计算机中的存储结构以及各种操作的算法设计。

1.2:数据:是客观描述事物的数字、字符以及所有的能输入到计算机中并能被计算机接收的各种集合的统称。

数据元素:表示一个事物的一组数据称作是一个数据元素,是数据的基本单位。

数据项:是数据元素中有独立含义的、不可分割的最小标识单位。

数据结构概念包含三个方面:数据的逻辑结构、数据的存储结构的数据的操作。

1.3数据的逻辑结构指数据元素之间的逻辑关系,用一个数据元素的集合定义在此集合上的若干关系来表示,数据结构可以分为三种:线性结构、树结构和图。

1.4:数据元素及其关系在计算机中的存储表示称为数据的存储结构,也称为物理结构。

数据的存储结构基本形式有两种:顺序存储结构和链式存储结构。

2.1:算法:一个算法是一个有穷规则的集合,其规则确定一个解决某一特定类型问题的操作序列。算法规则需满足以下五个特性:

输入——算法有零个或多个输入数据。
输出——算法有一个或多个输出数据,与输入数据有某种特定关系。
有穷性——算法必须在执行又穷步之后结束。
确定性——算法的每个步骤必须含义明确,无二义性。
可行性——算法的每步操作必须是基本的,它们的原则上都能够精确地进行,用笔和纸做有穷次就可以完成。
有穷性和可行性是算法最重要的两个特征。

2.2:算法与数据结构:算法建立数据结构之上,对数据结构的操作需用算法来描述。

算法设计依赖数据的逻辑结构,算法实现依赖数据结构的存储结构。

2.3:算法的设计应满足五个目标:

正确性:算法应确切的满足应用问题的需求,这是算法设计的基本目标。
健壮性:即使输入数据不合适,算法也能做出适当的处理,不会导致不可控结
高时间效率:算法的执行时间越短,时间效率越高。 果。
高空间效率:算法执行时占用的存储空间越少,空间效率越高。
可读性:算法的可读性有利于人们对算法的理解。
2.4:度量算法的时间效率,时间复杂度,(课本39页)。

2.5:递归定义:即用一个概念本身直接或间接地定义它自己。递归定义有两个条件:

至少有一条初始定义是非递归的,如1!=1.
由已知函数值逐步递推计算出未知函数值,如用(n-1)!定义n!。
第二章:线性表
1.1线性表:线性表是由n(n>=0)个类型相同的数据元素a0,a1,a2,…an-1,组成的有限序列,记作: LinearList = (a0,a1,a2,…an-1)

其中,元素ai可以是整数、浮点数、字符、也可以是对象。n是线性表的元素个数,成为线性表长度。若n=0,则LinearList为空表。若n>0,则a0没有前驱元素,an-1没有后继元素,ai(0<i<n-1)有且仅有一个直接前驱元素ai-1和一个直接后继元素ai+1。

1.2线性表的顺序存储是用一组连续的内存单元依次存放线性表的数据元素,元素在内存的物理存储次序与它们在线性表中的逻辑次序相同。

线性表的数据元素数据同一种数据类型,设每个元素占用c字节,a0的存储地址为

Loc(a0),则ai的存储地址Loc(ai)为:Loc(ai) = Loc(a0)+ i*c

数组是顺序存储的随机存储结构,它占用一组连续的存储单元,通过下标识别元素,元素地址是下标的线性函数。

1.3:顺序表的插入和删除操作要移动数据元素。平均移动次数是 属数据表长度的一半。(课本第50页)

1.4:线性表的链式存储是用若干地址分散的存储单元存储数据元素,逻辑上相邻的数据元素在物理位置上不一定相邻,必须采用附加信息表示数据元素之间的顺序关系。

它有两个域组成:数据域和地址域。通常成为节点。(课本第55页及56页)

1.5单链表(课本56页)

单链表的遍历:Node<E> p = head; while(p!=null){ 访问p节点;p = p.next;}

单链表的插入和删除操作非常简便,只要改变节点间的链接关系,不需移动数据元素。

单链表的插入操作:1):空表插入/头插入 2)中间插入/尾插入

if(head == null) Node<E> q = new Node<E>(x);

{ head = new Node<E>(x); q.next = p.next;

}else{ p.next = q;

Node<E> q=new Node<E>(x); 中间插入或尾插入都不会改变单表

q.next = head; 的头指针head。

head = q;

}

单链表的删除操作:

头删除:head = head.next;
中间/尾删除:if(p.next!=null){ p.next = p.next.next;}
循环单链表:如果单链表最后一个节点的next链保存单链表的头指针head值,则该单链表成为环形结构,称为循环单链表。(课本67)

若rear是单链表的尾指针,则执行(rear.next=head;)语句,使单链表成为一条循环单链表。当head.next==head时,循环单链表为空。

1.6:双链表结构:双链表的每个结点有两个链域,分别指向它的前驱和后继结点,

当head.next==null时,双链表为空。

设p指向双链表中非两端的某个结点,则成立下列关系:p=p.next.prev=p.prev.next。

双链表的插入和删除:1)插入 2)删除

q=new DLinkNode(x); p.prev.next = p.next;

q.prev=p.prev;q.next =p; if(p.next=null){

p.prev.next = q;p.prev=q; (p.next).prev = p.prev;}

循环双链表:当head.next==head且head.prev==head时,循环双链表为空。

第三章:栈和队列
1.1栈:栈是一种特殊的线性表,其中插入和删除操作只允许在线性表的一端进行。允许操作的一端称为栈顶,不允许操作的一端称为栈底。栈有顺序栈和链式栈。

栈中插入元素的操作称为入栈,删除元素的操作称为出栈。没有元素的中称为空栈。

栈的进出栈顺序:后进先出,先进后出。(及75页的思考题)。

1.2:队列:队列是一种特殊的线性表,其中插入和删除操作分别在线性表的两端进行。

向队列中插入元素的过程称为入队,删除元素的过程称为出对,允许入队的一端称为队尾,允许出队的一端称为对头。没有元素的队列称为空队列。队列是先进先出。

第四章:串
1.1:串是一种特殊的线性表,其特殊性在于线性表中的每个元素是一个字符。一个串记为: s=“s0s1s2…sn-1” 其中n>=0,s是串名,一对双引号括起来的字符序列s0s1s2…sn-1是串值,si(i=0,1,2,…n-1)为特定字符集合中的一个字符。一个串中包含的字符个数称为串的长度。

长度为0的串称为空串,记作“”,而由一个或多个空格字符构成的字符串称为空格串。

子串:由串s中任意连续字符组成的一个子序列sub称为s的子串,s称为sub的主串。子串的序号是指该子串的第一个字符在主串中的序号。

串比较:两个串可比较是否相等,也可比较大小。两个串(子串)相等的充要条件是两个串(子串)的长度相同,并且各对应位置上的字符也相同。

两个串的大小由对应位置的第一个不同字符的大小决定,字符比较次序是从头开始依次向后。当两个串长度不等而对应位置的字符都相同时,较长的串定义为较“大”。

第五章:数组和广义表
1.1:数组是一种数据结构,数据元素具有相同的数据类型。一维数组的逻辑结构是线性表,多维数组是线性表的扩展。

1.2:一维数组:一维数组采用顺序存储结构。一个一维数组占用一组连续的存储单元。

设数组第一个元素a0的存储地址为Loc(a0),每个元素占用c字节,则数组其他元素ai的存储地址Loc(ai)为: Loc(ai)= Loc(a0)+i*c

数组通过下标识别元素,元素地址是下标的线性函数。一个下标能够唯一确定一个元素,所划给的时间是O(1)。因此数组是随机存取结构,这是数组最大的优点。

1.3:多维数组的遍历:有两种次序:行主序和列主序。

行主序:以行为主序,按行递增访问数组元素,访问完第i行的所有元素之后再访问第i+1行的元素,同一行上按列递增访问数组元素。
a00,a01,…a0(n-1), a10,a11,…a1(n-1),…a(m-1)0,a(m-1)1,…,a(m-1)(n-1)

2)列主序:以列为主序,按列递增访问数组元素,访问完第j列的所有元素之后再访问第j+1列的元素,同一列上按列递增访问数组元素。

多维数组的存储结构:多维数组也是由多个一维数组组合而成,组合方式有一下两种。

静态多维数组的顺序存储结构:可按行主序和列主序进行顺序存储。
按行主序存储时,元素aij的地址为:Loc(aij)= Loc(a00)+(i*n+j)*c

按列主序存储时,Loc(aij)= Loc(a00)+(j*m+i)*c

动态多维数组的存储结构。
二维数组元素地址就是两个下标的线性函数。无论采用哪种存储结构,多维数组都是基于一维数组的,因此也只能进行赋值、取值两种存取操作,不能进行插入,删除操作。

第六章:

树是数据元素(结点)之间具有层次关系的非线性结构。在树结构中,除根以外的结点只有一个直接前驱结点,可以有零至多个直接后继结点。根没有前驱结点。

树是由n(n>=0)个结点组成的有限集合(树中元素通常称为结点)。N=0的树称为空树;n>0大的树T;

@有一个特殊的结点称为根结点,它只有后继结点,没有前驱结点。

@除根结点之外的其他结点分为m(m>=0)个互不相交的集合T0,T1,T3……..,Tm-1,其中每个集合Ti(0<=i<m)本身又是一棵树,称为根的子树。

树是递归定义的。结点是树大的基本单位,若干个结点组成一棵子树,若干棵互不相交的子树组成一棵树。树的每个结点都是该树中某一棵子树的根。因此,树是由结点组成的、结点之间具有层次关系大的非线性结构。

结点的前驱结点称为其父母结点,反之,结点大的后继结点称为其孩子结点。一棵树中,只有根结点没有父母结点,其他结点有且仅有一个父母结点。

拥有同一个父母结点的多个结点之间称为兄弟结点。结点的祖先是指从根结点到其父母结点所经过大的所有结点。结点的后代是指该结点的所有孩子结点,以及孩子的孩子等。

结点的度是结点所拥有子树的棵数。度为0的结点称为叶子结点,又叫终端结点;树中除叶子结点之外的其他结点称为分支结点,又叫非叶子结点或非终端结点。树的度是指树中各结点度的最大值。

结点的层次属性反应结点处于树中的层次位置。约定根结点的层次为1,其他结点的层次是其父母结点的层次加1。显然,兄弟结点的层次相同。

树的高度或深度是树中结点的最大层次树。

设树中x结点是y结点的父母结点,有序对(x,y)称为连接这两个结点的分支,也称为边。

设(X0,X1,….,Xk-1)是由树中结点组成的一个序列,且(Xi,Xi+1)(0<=i<k-1)都是树中的边,则该序列称为从X0到Xk-1的一条路径。路径长度为路径上的边数。

在树的定义中,结点的子树T0,T1…..,Tm-1之间没有次序,可以交换位置,称为无序树,简称树。如果结点的子树T0,T1……,Tm-1从左到右是有次序的,不能交换位置,则 称该树为有序树。

森林是m(m>=0)棵互不相干的树的集合。给森林加上一个根结点就变成一棵树,将树的根节点删除就变成森林。

二叉树的性质1:若根结点的层次为1,则二叉树第i层最多有2 的i-1次方(i>=1)个结点。

二叉树的性质2:在高度为k的二叉树中,最多有2的k次方减一个结点。

二叉树的性质3:设一棵二叉树的叶子结点数为n0,2度结点数为n2,则n0=n2+1。

一棵高度为k的满二叉树是具有2的k次方减一个结点的二叉树。满二叉树中每一层的结点数目都达到最大值。对满二叉树的结点进行连续编号,约定根节点的序号为0,从根节点开始,自上而下,每层自左至右编号。

一棵具有n个结点高度为k的二叉树,如果他的每个节点都与高度为k的满二叉树中序号为0~n-1

的结点一一对应,则这棵二叉树为为完全二叉树。

满二叉树是完全二叉树,而完全二叉树不一定是满二叉树。完全二叉树的第1~k-1层是满二叉树第k层不满,并且该层所有结点必须集中在该层左边的若干位置上。

二叉树的性质4:一棵具有n个结点的完全二叉树,其高度k=log2n的绝对值+1

二叉树的性质5:一棵具有n个结点的完全二叉树,对序号为i的结点,有

@若i=0,则i为根节点,无父母结点;若i>0,则i的父母结点的序号为[(i-1)/2]。

@若2i+1<n,则i的左孩子结点序号为2i+1;否则i无左孩子。

@若2i+2<n,则i的右孩子结点的序号为2i+2,否则i无右孩子。

二叉树的遍历

二叉树的遍历是按照一定规则和次序访问二叉树中的所有结点,并且每个结点仅被访问一次。

二叉树的三种次序遍历

1:先根次序;访问根节点,遍历左子树,遍历右子树。

2:中根次序;遍历左子树,访问右子树,遍历右子树。

3:后根次序;遍历左子树,遍历右子树,访问根节点。

先根次序遍历时,最先访问根节点;后根次序遍历时,最后访问根节点;中根次序遍历时,左子树上的结点在根节点之前访问,右子树上的结点在根节点之后访问。

二叉树的插入和删除操作P147

二叉树的层次遍历P149

习题P167 6—10,6—19

第七章

图是由定点集合及顶点间的关系集合组成的一种数据关边系。顶点之间的关系成为边。一个图G记为G=(V,E),V是顶点A的有限集合,E是边的有限集合。即 V={A|A属于某个数据元素集合}

E={(A,B)|A,B属于V}或E={<A,B>|A,B属于V且Path(A,B)}其中Path(A,B)表示从顶点A到B的一条单向通路,即Path(A,B)是有方向的。

无向图中的边事没有方向,每条边用两个顶点的无序对表示。

有向图中的边是有方向,每条边用两个顶点的有序对表示。

完全图指图的边数达到最大值。n个顶点的完全图记为Kn。无向完全图Kn的边数为n*(n-1)/2,有向完全图Kn的边数为n*(n-1)。

子图:设图G==(V,E),G’=(V’,E’),若V’包含于V且E’包含于E,则称图G’是G的子图。若G’是G的真子图。

连通图:在无向图G中,若从顶点VI到Vj有路径,则称Vi和Vj是联通的。若图G中任意一对顶点Vi和Vj(Vi不等于Vj)都是联通的,则称G为连通图。非连通图的极大联通子图称为该图的联通分量。

强连通图:在有向图中,若在每一对顶点Vi和Vj(Vi不等于Vj)之间都存在一条从Vi到Vj的路径,也存在一条从Vi到Vj的路径,也存在一条从Vi到Vj的路径,则称该图的强连通图。非强连通图的极大强连通子图称为该图的强连通图分量。

图的遍历

遍历图是指从图G中任意一个顶点V出发,沿着图中的边前行,到达并访问图中的所有顶点,且每个顶点仅被访问一次。遍历图要考虑一下三个问题:

@指定遍历的第一个访问顶点

@由于一个顶点可能与多个顶点相邻,因此要在多个邻接顶点之间约定一种访问次序。

@由于图中可能存在回路,在访问某个顶点之后,可能沿着某条路径又回到该顶点。

深度优先搜索

图的深度优先搜索策略是,访问某个顶点v,接着寻找v的另一个未被访问的邻接顶点w访问,如此反复执行,走过一条较长路径到达最远顶点;若顶点v没有未被访问的其他邻接顶点,则回到前一个被访问顶点,再寻找其他访问路径。

图的深度优先搜索遍历算法P188

联通的无回路的无向图,简称树。树中的悬挂点又成为树叶,其他顶点称为分支点。各连通分量均为树的图称为森林,树是森林。

由于树中无回路,因此树中必定无自身环也无重边(否则他有回路)若去掉树中的任意一条边,则变成森林,成为非联通图;若给树加上一条边,形成图中的一条回路,则不是树。P191

生成树和生成森林:

一个连通无向图的生成树是该图的一个极小联通生成子图,它包含原图中所有顶点(n个)以及足以构成一棵树的n-1条边。

一个非联通的无向图,其各连通图分量的生成图组成该图的生成森林。

图的生成图或生成森林不是唯一的,从不同顶点开始、采用不同遍历可以得到不同的生成树或森林。

在生成树中,任何树中,任何两个顶点之间只有唯一的一条路径。

第八章

折半查找算法描述 P206,P207

二叉排序树及其查找:

二叉排序树或者是一棵空树;或者是具有下列性质的二叉树:

@每个结点都有一个作为查找依据的关键字,所有结点的关键字互不相同。

@若一个结点的左子树不空,则左子树上所有结点的关键字均小于这个节点的关键字;

@每个结点的左右子树也分别为二叉排序树。

在一棵二叉排序树中,查找值为value的结点,算法描述如下:

@从根结点开始,设p指向根结点

@将value与p结点的关键字进行比较,若两者相等,则查找成功;若value值较小,则在p的左子树中继续查找;若value值较大,则在p的右子树中继续查找。

@重复执行上一步,直到查找成功或p为空,若p为空,则查找不成功。

习题 8-6

第九章

直接插入排序算法描述:p228

冒泡排序算法的描述:p232

快速排序算法描述p233

直接选择排序算法描述p236

直接选择排序算法实现如下:

Public static void selectSort(int[]table){

for(int i=0;i<table.length-1;i++){

int min=I;

for(int j=i+1;j<table.length;j++){

if(table[j]<table[min])

min=j;

if(min!=i){

int temp=table[i];

table[i]==table[min];

table[min]=temp;

}

}

}

}

堆排序是完全二叉树的应用,是充分利用完全二叉树特性的一种选择排序。

堆定义:设n个元素的数据序列{k0,k1,。。。。kn-1},当且仅当满足下列关系

k1<=k2i+1且ki<=k2i+2 i=0,1,2,3,….,[n/2-1]

或ki>==k2i+1且ki>=2i+2i=0,1,2,3,…..[n/2-1]时,序列{k0,k1…….kn-1}称为最小堆或最大堆。将最小(大)堆看成是一颗完全二叉树的层次遍历序列,则任意一个结点的关键字都小于等于(大于等于)它的孩子节点的关键字值,由此可知,根结点值最小(大)。根据二叉树的性质5,完全二叉树中的第i(0<=i<n)个结点,如果有孩子,则左孩子为第2i+1个结点,右孩子为第2i+2个结点。

希望对你会有所帮助。

㈤ 用算法实现:单链表和顺序表删除。删除顺序表中值相同的多余结点

第8章排序(算法设计)习题练习答案
作者: 来源: http://www.csai.cn 2006年9月4日

13. 将哨兵放在R[n]中,被排序的记录放在R[0..n-1]中,重写直接插入排序算法。
解:
重写的算法如下:
void InsertSort(SeqList R)
{//对顺序表中记录R[0..n-1]按递增序进行插入排序
int i,j;
for(i=n-2;i>=0;i--) //在有序区中依次插入R[n-2]..R[0]
if(R[i].key>R[i+1].key) //若不是这样则R[i]原位不动
{
R[n]=R[i];j=i+1; //R[n]是哨兵
do{ //从左向右在有序区中查找插入位置
R[j-1]=R[j]; //将关键字小于R[i].key的记录向右移
j++;
}while(R[j].key<R[n].key]);
R[j-1]=R[n]; //将R[i]插入到正确位置上
}//endif
}//InsertSort.

14.以单链表作为存储结构实现直接插入排序算法。
解:
#define int KeyType //定义KeyType 为int型
typedef struct node{
KeyType key; //关键字域
OtherInfoType info; //其它信息域,
struct node * next; //链表中指针域
}RecNode; //记录结点类型
typedef RecNode * LinkList ; //单链表用LinkList表示

void InsertSort(LinkList head)
{//链式存储结构的直接插入排序算法,head是带头结点的单链表
RecNode *p,*q,*s;
if ((head->next)&&(head->next->next))//当表中含有结点数大于1
{
p=head->next->next;//p指向第二个节点
head->next=NULL;
q=head;//指向插入位置的前驱节点
while(p)&&(q->next)&&(p->key<q->next->key)
q=q->next;
if (p)
{s=p;p=p->next;// 将要插入结点摘下
s->next=q->next;//插入合适位置:q结点后
q->next=s;
}
}
}

15.设计一算法,使得在尽可能少的时间内重排数组,将所有取负值的关键字放在所有取非负值的关键字之前。请分析算法的时间复杂度。
解:
因为只需将负数关键字排在前面而无需进行精确排列顺序,因此本算法采用两端扫描的方法,就象快速排序采用的方法一样,左边扫描到正数时停止,开始扫描右边,遇到负数时与左边的当前记录交换,如此交替进行,一趟下来就可以完成排序。

void ReSort(SeqList R)
{//重排数组,使负值关键字在前
int i=1,j=n; //数组存放在R[1..n]中
while (i<j) //i<j表示尚未扫描完毕
{ while(i<j&&R[i].key<0) //遇到负数则继续扫描
i++;
R[0]=R[i]; //R[0]为辅助空间
while(i<j&&R[j].key>=0)// 遇到正数则继续向左扫描
j--;
R[i++]=R[j];R[j--]=R[0];//交换当前两个元素并移动指针
}//endwhile
}//ReSort

本算法在任何情况下的比较次数均为n(每个元素和0)相比,交换次数少于n/2,总的来说,时间复杂度为O(n).

*16.写一个双向冒泡排序的算法,即在排序过程中交替改变扫描方向。
解:
算法如下:
void BubbleSort(SeqList R)
{//R[1..n]是待排序文件,双向扫描冒泡排序
int i,j,k;
Boolean exchange; //交换标记
i=n;j=1;
exchange=TRUE;
while (i>j)&&(exchange)
{k=i-1;exchange=FALSE;
while (k>=j)//由下往上扫描
{if (r[k]>r[k+1])
{r[0]=r[k];r[k]=r[k+1];r[k+1]=r[k];exchange=TRUE;//交换
}//endif
k--;
}//endwhile
if (exchange)
{exchange=FALSE;
j++;k=j+1;
while(k<=i)//由上往下扫描
{if (r[k]<r[k-1])
{r[0]=r[k];r[k]=r[k-1];r[k-1]=r[k];exchange=TRUE;//交换
}//endif
k++;
}endwhile
i--;
}//endif
}endwhile
}//endsort

17.下面是一个自上往下扫描的冒泡排序的伪代码算法,它采用lastExchange 来记录每趟扫描中进行交换的最后一个元素的位置,并以它作为下一趟排序循环终止的控制值。请仿照它写一个自下往上扫描的冒泡排序算法。
void BubbleSort(int A[],int n)
//不妨设A[0..n-1]是整型向量
int lastExchange,j,i=n-1;
while (i>0)
lastExchange=0;
for(j=0;j<i;j++)//从上往下扫描A[0..i]
if(A[j+1]<A[j]){
交换A[j]和A[j+1];
lastExchange=j;
}
i=lastExchange;//将i置为最后交换的位置
}//endwhile
}//BubbleSort

解:算法如下:
void BubbleSort(int A[],int n)
//不妨设A[0..n-1]是整型向量
int lastExchange,j,i=0;
while (i<n) //这一条很重要,如不改为这样,算法将无限循环下去
lastExchange=n;
for(j=n-1;j>i;j--)//从下往上扫描A[0..i]
if(A[j-1]<A[j]){
交换A[j]和A[j-1];
lastExchange=j;
}
i=lastExchange;//将i置为最后交换的位置
}//endwhile
}//BubbleSort

18.改写快速排序算法,要求采用三者取中的方式选择划分的基准记录;若当前被排序的区间长度小于等于3时,无须划分而是直接采用直接插入方式对其排序。
解:
改写后的算法如下:
void QuickSort(SeqList R,int low ,int high)
{//对R[low..high]快速排序
int pivotpos;
if(high-low<=2)//若当前区内元素少于3个
{//则进行直接插入排序
InsertSort(R,low,high);
}
else
{
pivotpos=midPartion(R,low,high);
QuickSort(R,low,pivotpos-1);
QuickSort(R,pivotpos+1,high);
}
}//QuickSort

int midPartion(SeqList R,int i, int j)
{//三者取中规则定基准
if(R[(i+j)/2].key>R[i].key)
{ 交换R[(i+j)/2]和R[i];}
if(R[i].key>R[j].key)
{ 交换R[i]和R[j];}
if(R[i].key)<R[(i+j)/2].key)
{ 交换R[i]和R[(i+j)/2];}
//以上三个if语句就使区间的第一个记录的key值为三个key的中间值
return Partion(R,i,j);//这样我们就可以仍使用原来的划分算法了
}

19.对给定的j(1≤j≤n ),要求在无序的记录区R[1..n]中找到按关键字自小到大排在第j个位置上的记录(即在无序集合中找到第j个最小元),试利用快速排序的划分思想编写算法实现上述的查找操作。
答:
int QuickSort(SeqList R,int j,int low,int high)
{ //对R[low..high]快速排序
int pivotpos; //划分后的基准记录的位置
if(low<high){//仅当区间长度大于1时才须排序
pivotpos=Partition(R,low,high); //对R[low..high]做划分
if (pivotpos==j) return r[j];
else if (pivotpos>j) return(R,j,low,pivotpos-1);
else return quicksort(R,j,pivotpos+1,high);
}
} //QuickSort

20.以单链表为存储结构,写一个直接选择排序算法。
答:
#define int KeyType //定义KeyType 为int型
typedef struct node{
KeyType key; //关键字域
OtherInfoType info; //其它信息域,
struct node * next; //链表中指针域
}RecNode; //记录结点类型

typedef RecNode * LinkList ; //单链表用LinkList表示

void selectsort(linklist head)
{RecNode *p,*q,*s;
if(head->next)&&(head->next->next)
{p=head->next;//p指向当前已排好序最大元素的前趋
while (p->next)
{q=p->next;s=p;
while(q)
{if (q->key<s->key) s=q;
q=q->next;
}//endwhile
交换s结点和p结点的数据;
p=p->next;
}//endwhile
}//endif
}//endsort

21.写一个heapInsert(R,key)算法,将关键字插入到堆R中去,并保证插入R后仍是堆。提示:应为堆R增加一个长度属性描述(即改写本章定义的SeqList类型描述,使其含有长度域);将key先插入R中已有元素的尾部(即原堆的长度加1的位置,插入后堆的长度加1),然后从下往上调整,使插入的关键字满足性质。请分析算法的时间。
答:
#define n 100//假设文件的最长可能长度
typedef int KeyType; //定义KeyType 为int型
typedef struct node{
KeyType key; //关键字域
OtherInfoType info; //其它信息域,
}Rectype; //记录结点类型

typedef struct{
Rectype data[n] ; //存放记录的空间
int length;//文件长度
}seqlist;

void heapInsert(seqlist *R,KeyType key)
{//原有堆元素在R->data[1]~R->data[R->length],
//将新的关键字key插入到R->data[R->length+1]位置后,
//以R->data[0]为辅助空间,调整为堆(此处设为大根堆)
int large;//large指向调整结点的左右孩子中关键字较大者
int low,high;//low和high分别指向待调整堆的第一个和最后一个记录
int i;
R->length++;R->data[R->length].key=key;//插入新的记录
for(i=R->length/2;i>0;i--)//建堆
{
low=i;high=R->length;
R->data[0].key=R->data[low].key;//R->data[low]是当前调整的结点
for(large=2*low;large<=high;large*=2){
//若large>high,则表示R->data[low]是叶子,调整结束;
//否则令large指向R->data[low]的左孩子
if(large<high&&R->data[large].key<R->data[large+1].key)
large++;//若R->data[low]的右孩子存在
//且关键字大于左兄弟,则令large指向它
if (R->data[0].key<R->data[large].key)
{ R->data[low].key= R->data[large].key;
low=large;//令low指向新的调整结点
}
else break;//当前调整结点不小于其孩子结点的关键字,结束调整
}//endfor
R->data[low].key=R->data[0].key;//将被调整结点放入最终的位置上
}//end of for
}end of heapinsert

算法分析:
设文件长度为n,则该算法需进行n/2趟调整,总的时间复杂度与初建堆类似,最坏时间复杂度为O(nlgn),辅助空间为O(1).

22.写一个建堆算法:从空堆开始,依次读入元素调用上题中堆插入算法将其插入堆中。
答:
void BuildHeap(seqlist *R)
{
KeyType key;
R->length=0;//建一个空堆
scanf("%d",&key);//设MAXINT为不可能的关键字
while(key!=MAXINT)
{
heapInsert(R,key);
scanf("%d",&key);
}
}

23.写一个堆删除算法:HeapDelete(R,i),将R[i]从堆中删去,并分析算法时间,提示:先将R[i]和堆中最后一个元素交换,并将堆长度减1,然后从位置i开始向下调整,使其满足堆性质。
答:
void HeapDelete(seqlist *R,int i)
{//原有堆元素在R->data[1]~R->data[R->length],
//将R->data[i]删除,即将R->data[R->length]放入R->data[i]中后,
//将R->length减1,再进行堆的调整,
//以R->data[0]为辅助空间,调整为堆(此处设为大根堆)
int large;//large指向调整结点的左右孩子中关键字较大者
int low,high;//low和high分别指向待调整堆的第一个和最后一个记录
int j;
if (i>R->length)
Error("have no such node");
R->data[i].key=R->data[R->length].key;
R->length--;R->data[R->length].key=key;//插入新的记录
for(j=i/2;j>0;j--)//建堆
{
low=j;high=R->length;
R->data[0].key=R->data[low].key;//R->data[low]是当前调整的结点
for(large=2*low;large<=high;large*=2){
//若large>high,则表示R->data[low]是叶子,调整结束;
//否则令large指向R->data[low]的左孩子
if(large<high&&R->data[large].key<R->data[large+1].key)
large++;//若R->data[low]的右孩子存在
//且关键字大于左兄弟,则令large指向它
if (R->data[0].key<R->data[large].key)
{ R->data[low].key= R->data[large].key;
low=large;//令low指向新的调整结点
}
else break;//当前调整结点不小于其孩子结点的关键字,结束调整
}//endfor
R->data[low].key=R->data[0].key;//将被调整结点放入最终的位置上
}//end of for
}end of HeapDelete

24.已知两个单链表中的元素递增有序,试写一算法将这两个有序表归并成一个递增有序的单链表。算法应利用原有的链表结点空间。
答:
typedef struct node{
KeyType key; //关键字域
OtherInfoType info; //其它信息域,
struct node * next; //链表中指针域
}RecNode; //记录结点类型

typedef RecNode * LinkList ; //单链表用LinkList表示

void mergesort(LinkList la,LinkList lb,LinkList lc)
{RecNode *p,*q,*s,*r;
lc=la;
p=la;//p是la表扫描指针,指向待比较结点的前一位置
q=lb->next;//q是lb表扫描指针,指向比较的结点
while(p->next)&&(q)
if (p->next->key<=q->key)
p=p->next;
else {s=q;q=q->next;
s->next=p->next;p->next=s;//将s结点插入到p结点后
p=s;}
if (!p->next) p->next=q;
free(lb);
}

25.设向量A[0..n-1]中存有n个互不相同的整数,且每个元素的值均在0到n-1之间。试写一时间为O(n)的算法将向量A排序,结果可输出到另一个向量B[0..n-1]中。
答:
sort(int *A,int *B)
{//将向量A排序后送入B向量中
int i;
for(i=0;i<=n-1;i++)
B[A[i]]=A[i];
}

*26.写一组英文单词按字典序排列的基数排序算法。设单词均由大写字母构成,最长的单词有d个字母。提示:所有长度不足d个字母的单词都在尾处补足空格,排序时设置27个箱子,分别与空格,A,B...Z对应。
答:
#define KeySize 10 //设关键字位数d=10
#define Radix 27 //基数rd为27
typedef RecType DataType;//将队列中结点数据类型改为RecType类型
typedef struct node{
char key[KeySize]; //关键字域
OtherInfoType info; //其它信息域,
}RecType; //记录结点类型
typedef RecType seqlist[n+1];

void RadixSort(seqlist R)
{
LinkQueue B[Radix];
int i;
for(i=0;i<Radix;i++)//箱子置空
InitQueue(&B[i]);
for(i=KeySize-1;i>=0;i--){//从低位到高位做d趟箱排序
Distribute(R,B,i);//第KeySize-i趟分配
Collect(R,B);//第KeySize-i趟收集
}
}

void Distribute(seqlist R,LinkQueue B[], int j)
{//按关键字的第j个分量进行分配,初始时箱子为空
int i;
j=KeySize-j; // 确定关键字从低位起的位置
for(i=0;i<n;i++) //依次扫描R[i],将其装箱
if (R[i].key[j]-'A'>26)
EnQueue(&B[0],R[i]);//将第j位关键字位空格的记录入第0个队列
else EnQueue(&B[0],R[R[i].key[j]-'A'+1]);
}

void Collect(seqlist R,LinkQueue B[])
{
//依次将各非空箱子中的记录收集起来,本过程结束,各箱子都变空
int i,j;
for (j=0;j<Radix;j++)
while(!QueueEmpty(&B[j]))
R[i++]=DeQueue(&B[j]);//将出队记录依次输出到R[i]中
}

热点内容
左端算法 发布:2025-08-24 21:53:26 浏览:526
安卓系统怎么编译环境 发布:2025-08-24 21:53:24 浏览:780
java转义符 发布:2025-08-24 21:48:26 浏览:65
powershell脚本识别 发布:2025-08-24 21:42:30 浏览:967
压缩机企业 发布:2025-08-24 21:35:14 浏览:924
三星证书存储 发布:2025-08-24 21:29:27 浏览:910
古诗文源码 发布:2025-08-24 21:20:15 浏览:400
androidxml字符 发布:2025-08-24 20:47:31 浏览:53
php页面跳转参数 发布:2025-08-24 20:46:25 浏览:829
java的常用设计模式 发布:2025-08-24 20:36:52 浏览:311