个人总结 禁止外传
真题记录
西北大学2010年招收攻读硕士学位研究生试题
一、简答题【共30分,每小题6分】
1. 简述字符串、栈属于线性表原因。
答案:
字符串是一种特定的线性表,其特殊性就在于组成线性表的每个元素就是一个单字符。栈是一种限定性线性表,是将线性表的插入和删除操作限制为仅在表的一端进行。
解释:
字符串和栈之所以被认为是线性表的一种,主要是因为它们满足线性表的基本特性和操作。线性表是一种线性结构,它是一系列元素的有限序列,其中元素之间具有一对一的相邻关系,除了第一个元素和最后一个元素外,每个元素都恰好有一个前驱和一个后继。线性表的基本操作包括查找、插入、删除等。下面分别解释字符串和栈为何属于线性表:
字符串
字符串是由零个或多个字符组成的有限序列。这些字符之间按照顺序排列,形成了一种线性关系。具体来说:
- 有序性:字符串中的字符按照从左到右的顺序排列,这种顺序是不可变的(除非对字符串进行编辑操作)。这种有序性正是线性表的一个关键特性。
- 有限性:字符串中的字符数量是有限的,这符合线性表元素数量的有限性要求。
- 线性关系:字符串中的每个字符都只有一个前驱字符(除了第一个字符)和一个后继字符(除了最后一个字符),这完全符合线性表中元素之间的线性关系。
因此,字符串可以被看作是一种特殊的线性表,其中元素是字符。
栈
栈(Stack)是一种遵循后进先出(LIFO, Last In First Out)原则的有序集合。栈同样满足线性表的基本特性:
- 有序性:栈中的元素虽然进出栈的顺序受到严格限制,但它们仍然是有序的。具体来说,最先进入栈的元素将是最后被移除的,这种顺序性体现了线性表的有序性。
- 有限性:栈的容量是有限的,这意味着栈中元素的数量不能无限增加,这符合线性表元素数量的有限性要求。
- 线性关系:尽管栈的访问和操作受到限制(只能通过栈顶进行),但栈中的元素仍然保持着一种线性的关系。每个元素(除了栈顶元素)都有一个确定的后继元素(即栈中该元素之上的元素),而栈底元素则没有前驱元素。这种关系虽然不是完全意义上的双向线性关系(因为前驱元素的访问受到限制),但仍然可以视为一种特殊的线性关系。
综上所述,字符串和栈都因为满足线性表的基本特性和操作,而被归类为线性表的一种。不过,它们各自具有特定的操作限制和用途,这使得它们在实际应用中具有独特的价值。
2. 线性结构与非线性结构的差别。
线性结构与非线性结构是计算机科学中描述数据组织方式的重要概念,它们之间的主要差别体现在以下几个方面(随便回答一两个方面即可):
- 存储方式和组织关系
- 线性结构:数据元素之间是一对一的线性关系,即每个元素(除了第一个和最后一个)都有一个前驱和一个后继。这种结构中的数据元素按顺序排列,形成一个有“头”有“尾”的序列。常见的线性结构包括数组、链表、栈和队列等。
- 非线性结构:数据元素之间不是一对一的关系,而是一对多或多对多的关系。这种结构中的数据元素不一定保持一个线性序列,每个元素可能与零个或多个其他元素有联系。常见的非线性结构包括树形结构、图形结构等。
- 遍历方式
- 线性结构:由于其元素之间的线性关系,线性结构可以在一次运行中完全遍历。这意味着从第一个元素开始,可以顺序地访问到最后一个元素。
- 非线性结构:非线性结构的遍历通常比较复杂,因为它们包含分支和回路。遍历这种结构可能需要多次运行或使用特定的算法,如深度优先搜索(DFS)或广度优先搜索(BFS)。
- 内存使用
- 线性结构:虽然线性结构在逻辑上非常直观和简单,但它们对内存的使用可能不是非常高效。特别是在某些情况下,如数组插入和删除元素时,可能需要移动大量元素以保持连续性。
- 非线性结构:非线性结构,如树和图,通常能够更有效地使用内存。它们通过节点和链接来组织数据,这种方式允许更灵活的内存分配和访问。
- 时间和空间复杂度
- 线性结构:线性结构的时间复杂度通常随着元素数量的增加而线性增长。然而,在某些操作中,如数组的中间插入和删除,时间复杂度可能会更高。
- 非线性结构:非线性结构的时间复杂度可能随着结构的复杂性和操作的类型而变化。在某些情况下,如树的平衡二叉搜索树(AVL树、红黑树等),时间复杂度可以保持在对数级别,这使得它们在某些应用中比线性结构更高效。
- 应用场景
- 线性结构:由于其简单性和直观性,线性结构在数据存储、算法实现和系统编程中有广泛应用。例如,数组和链表常用于存储和组织大量数据;栈和队列在算法实现中扮演重要角色,如深度优先搜索(DFS)和广度优先搜索(BFS)等。
- 非线性结构:非线性结构在表示具有复杂关系的数据时非常有用。例如,树形结构常用于表示具有层次关系的数据(如文件系统的目录结构、组织架构等);图形结构则常用于表示具有复杂网络关系的数据(如社交网络、交通网络等)。
综上所述,线性结构与非线性结构在存储方式、遍历方式、内存使用、时间和空间复杂度以及应用场景等方面存在显著差异。选择哪种结构取决于具体的应用需求和数据特性。
3. 算法定义与算法特性。
算法定义
算法通常表现为指令的有限序列,并且每条指令表示一个或多个操作。算法的目的是为了解决特定类型的问题,它规定了解决问题的运算过程。
算法特性
算法具有以下几个基本特性:
-
有穷性:
- 算法必须能在执行有限个步骤之后终止。这意味着算法不能陷入无限循环中,且每一步骤都应在有穷时间内完成。
-
确切性(或称确定性):
- 算法的每一个步骤必须有确切的定义,不能有歧义。这意味着算法的描述必须足够清晰,使得任何人都能按照描述准确地执行算法。
-
输入:
- 一个算法有0个或多个输入,这些输入是算法所需的初始量或被加工的对象的表示。输入取自特定的对象集合,用于刻画运算对象的初始情况。
-
输出:
- 一个算法有一个或多个输出,这些输出是与输入有特定关系的量,用于反映对输入数据加工后的结果。算法运行结束后必须有一个结果,如果算法没有输出,则相当于算法没有完成其预定的功能。
-
可行性:
- 算法中执行的任何计算步骤都可被分解为基本的可执行的操作步骤,这些步骤可以在相应的计算装置上实现。这要求算法中的操作必须是可行的,即可以在有限的时间和空间内完成。
4. 数据类型与抽象数据类型。
数据类型是一组性质相同的值集合以及定义在这个值集合上的一组操作的总称。抽象数据类型(ADT)定义了一个数据对象、数据对象中各元素间的结构关系以及一组处理数据的操作。
5. 图遍历中设置访问标志数组的作用
为了保证图中的各顶点在遍历过程中访问且仅访问一次,需要为每个顶点设一个访问标志,因此要为图设置一个访问标志数组,用于标示图中每个顶点是否被访问过。
二、方法选择【共20分,每小题10分】
1. 说明稳定排序含义,并给出一种不稳定排序方法的名称与证明。
稳定排序的含义是指,在排序过程中,如果两个或多个元素的关键字值相等,则它们在排序前后的相对位置保持不变。也就是说,待排序的记录序列中如果存在两个或两个以上关键字相等的记录,排序前的序列中某个记录Ri领先于另一个记录Rj(即i<j),那么在排序后的序列中Ri仍然领先于Rj,则称所用的排序方法是稳定的。
稳定排序的意义在于它能够保持具有相同属性的数据的原始插入顺序。这种特性在某些特定场景下非常有用,比如当需要根据多个属性对一组数据进行排序时,如果首先使用稳定的排序算法根据第一个属性进行排序,那么后续根据其他属性进行排序时,就可以利用之前排序的稳定性来避免重复排序或确保排序结果符合预期。
希尔排序{2,4,1,2}
2. 在一个连通无向图上,欲求从一点 Vi到另一点Vj(Vi≠ Vj)所经结点数目最短路径,在深度优先搜索、广度优先搜索、从一点到其余各顶点的最短路径算法中, 你认为最好选择哪种方法为基础,简述原因。
在求解从一点 V i V_i Vi 到另一点 V j V_j Vj(其中 V i ≠ V j V_i \neq V_j Vi=Vj)所经结点数目最短路径的问题时,我们需要考虑的是哪种算法能够最有效地找到这样的路径。以下是对深度优先搜索(DFS)、广度优先搜索(BFS)和从一点到其余各顶点的最短路径算法(如Dijkstra算法或Bellman-Ford算法)的评估及选择建议。
深度优先搜索(DFS)
- 特点:DFS通过递归或栈的方式尽可能深地搜索图的分支。它主要用于遍历或搜索树或图的全部节点,但不保证找到最短路径。
- 适用性:在寻找从 V i V_i Vi 到 V j V_j Vj 的最短路径时,DFS不是最佳选择,因为它可能深入搜索到与 V j V_j Vj 无关的路径,且不能保证找到的路径是最短的。
广度优先搜索(BFS)
- 特点:BFS从起始点开始,逐层向外扩展,直到找到目标点。它使用队列来实现层次遍历。
- 适用性:在求解两点间最短路径(尤其是无权图或所有边权重相等的图)时,BFS是最佳选择。因为它首先遍历所有与起点距离为1的节点,然后是距离为2的节点,依此类推,直到找到目标节点。这样找到的路径一定是最短的(在边权重相等的情况下)。
从一点到其余各顶点的最短路径算法(如Dijkstra算法或Bellman-Ford算法)
- 特点:
- Dijkstra算法:适用于带权重的有向图或无向图,但所有权重必须非负。它使用贪心策略来找到从单个源点到所有其他顶点的最短路径。
- Bellman-Ford算法:适用于可能包含负权边的图。它虽然能够处理负权边,但相对于Dijkstra算法来说效率较低。
- 适用性:虽然这些算法能够找到从一点到所有点的最短路径,但如果你只需要找到从 V i V_i Vi 到 V j V_j Vj 的最短路径,并且图的边权重可能为正、负或零,则Dijkstra算法(如果权重非负)或Bellman-Ford算法(如果可能包含负权边)是可行的选择。然而,与BFS相比,在边权重相等或均为正时,它们的实现可能更复杂且效率较低。
结论
在大多数情况下,如果图的边权重相等或均为正,且只需要找到从
V
i
V_i
Vi 到
V
j
V_j
Vj 的最短路径,推荐使用广度优先搜索(BFS)。因为它简单、高效,且能确保找到最短路径。如果图中存在负权边,则可能需要考虑使用Bellman-Ford算法。而Dijkstra算法则适用于边权重非负的情况,但相对于BFS来说,在处理两点间最短路径问题时可能不是最高效的选择。
三、构造结果【共40分,每小题10分】
1. 构造 10 个结点的折半判定树,并计算查找成功的平均査找长度。
2. 已知一二叉树中序序列为 BDAEC,后序序列为 DBECA,给出其对应的二叉树。
3. 已知 n阶下三角矩阵 A(即当 i<i 时,有aij=0),按照压缩存储的思想可以主对角线以下所有元素(包括主对角线上的元素)依次存放于一维数组B中。请从第一列开始,采用行序为主序,给出在B中确定元素aij存放位置的公式。
数组存储,需要展开讲一下。
4. 二叉排序树采用二叉链表方式存放,树中结点值各不相同,欲得到一个由小到大的结点值递增序列,简述处理方法思路。
根据二叉排序树的定义(左子树小于根节点,右子树大于根节点),根据二叉树中序遍历的定义(先访问左孩子,然后访问根节点,再访问右孩子),可以得出二叉排序树的一个重要性质,即中序遍历一个二叉树可以得到一个递增有序序列。
四、编写程序【共15分】
要求实现如下功能:
将数组C[0:n]中所有奇数移到偶数之前,要求时间复杂度为O(n)
要实现将数组 C[0:n]
中所有奇数移到偶数之前,同时保证时间复杂度为 O(n),我们可以采用双指针技术。具体来说,我们可以使用两个指针,一个指向数组的起始位置(我们称之为 left
),另一个指向数组的末尾位置(我们称之为 right
)。然后,我们从两端开始向中间遍历数组,当 left
指针指向偶数且 right
指针指向奇数时,交换这两个元素的位置,并同时移动两个指针。如果 left
指针指向奇数或 right
指针指向偶数,则只移动相应的指针。
function moveOddsToFront(C, n):
left = 0 # 起始索引
right = n - 1 # 末尾索引
while left < right:
# 如果左指针指向偶数
if C[left] % 2 == 0:
left += 1 # 移动左指针
# 如果右指针指向奇数
elif C[right] % 2 == 1:
right -= 1 # 移动右指针
# 如果左指针指向奇数且右指针指向偶数,则交换
else:
# 交换 C[left] 和 C[right]
temp = C[left]
C[left] = C[right]
C[right] = temp
left += 1
right -= 1
要求:将上述伪代码写为c语言函数
void move(SeqList *s){
int i=1;
int j=s->length;
int temp;
while(i<j){
while((i<j)&&(s->data[]%2==0))
j--;
while((i<j)&&(s->data[]%2==1))
i++;
if(i<j){
temp=s->data[i];
s->data[i]=s->data[j];
s->data[j]=temp;
}
}
}
五、编写算法【共30分,每小题15分】
1. 求二叉树的高度的算法。
int Get_tree_Level(BiTreeNode *root)
{
if (root == NULL)
return 0;
int left = 0, right = 0;
if (root->leftChild != NULL)
left = 1 + Get_tree_Level(root->leftChild);
if (root->rightChild != NULL)
right = 1 + Get_tree_Level(root->rightChild);
if (left >= right)
return left; //从左右子树挑出高的
else
return right;
}
2. 已知二叉树用二叉链表存储,要求写出算法,实现该二叉树左右子树交换。
typedef struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode;
void swapLeftRight(TreeNode *node) {
if (node == NULL) {
// 如果节点为空,则直接返回
return;
}
// 交换当前节点的左右子树
TreeNode *temp = node->left;
node->left = node->right;
node->right = temp;
// 递归地对左右子树执行相同的操作
swapLeftRight(node->left);
swapLeftRight(node->right);
}
六、编写算法【共15分】
void PrintTree(Tree tree){
Node *p;
if(tree==NULL) return 0;
if(tree->fch != NULL){
for(p=tree->fch;p!=NULL;p=p->nsib)
printf("%c,%c",tree->data,p->data);
}
if(tree->nsib!=NULL)
PrintTree(tree->nsib);
if(tree->fch!=NULL)
PrintTree(tree->fch);
}
西北大学2011年招收攻读硕士学位研究生试题
一、简答问题【共30分,每小题6分】
1. 四类数据结构名称及其关系图示。
集合结构,线性结构,树形结构,图形结构
2. 为什么说数组和广义表是线性表的推广?
当然可以,让我们更简单地解释为什么数组和广义表是线性表的推广:
数组是线性表的推广
线性表是一种有序的集合,其中的元素都是相同类型的,并且它们之间是一对一的关系。而数组可以看作是线性表的一种特殊形式,但它允许你定义元素的固定大小,并且可以是多维的。这意味着数组在保持线性表有序和元素关系的基础上,增加了对元素数量和维度的控制,从而能够存储更复杂的数据结构。
广义表是线性表的推广
广义表则更加灵活,它不仅仅限于存储相同类型的元素,而且允许元素本身也是广义表。这种嵌套结构使得广义表能够表示更加复杂和多样化的数据结构。在线性表中,元素是线性的、不可再分的;而在广义表中,元素可以是任意的,包括其他广义表,这极大地扩展了数据结构的表达能力。
简而言之,数组通过增加维度和固定大小来推广线性表,而广义表则通过允许元素嵌套和多样化来推广线性表。这两种结构都在不同的方面增强了线性表的能力,使其能够应对更复杂的数据存储和处理需求。
3. 算法的定义与特性
见过
4. 数据类型与抽象数据类型
见过
5. 图遍历算法中设置访问标志数组的作用
见过
二、方法选择【共20分,每小题10分】
1. 快速排序方法的最坏最好情况是什么,简要分析说明理由
快速排序(Quick Sort)是一种高效的排序算法,采用分而治之的策略来把一个序列分为较小和较大的两个子序列,然后递归地排序两个子序列。其性能高度依赖于所选的基准值(pivot)。
最好情况
最好情况发生在每次分区操作都能将数组分成大小相等的两部分。这意味着每次分区后,我们都可以将问题规模减半,从而形成一个深度为 l o g 2 n log_2 n log2n的递归树。在这种情况下,快速排序的时间复杂度为 O ( n l o g n ) O(n log n) O(nlogn)。这是因为每次递归调用处理的数据量是前一次的一半,而每层递归需要进行 O ( n ) O(n) O(n)的遍历来分区。
最坏情况
最坏情况发生在每次分区操作都将数组分成了一个空子数组和一个非空子数组(或接近这种情况)。这通常发生在数组已经是有序的(升序或降序),并且选择的基准值是数组中的最小或最大值时。在这种情况下,快速排序的性能退化为 O ( n 2 ) O(n^2) O(n2),因为每次递归调用都只会减少一个元素,需要 n − 1 n-1 n−1次递归调用才能达到排序完成的状态,而每次递归调用又都需要 O ( n ) O(n) O(n)的时间来遍历数组进行分区。
理由
- 最好情况:通过均匀分割数据,每次递归都能有效地减少问题规模,使得递归树的深度最小( l o g 2 n log_2 n log2n),从而保证了较高的效率。
- 最坏情况:由于数据分布极不均匀,每次递归调用只处理少量的数据,导致递归深度接近 n n n,且每层递归都需要遍历整个数组,从而产生了大量的重复工作,降低了效率。
为了避免最坏情况,通常采取的策略包括随机选择基准值(Randomized Quick Sort)或采用“三数取中”等方法来选择更合适的基准值,以提高算法的平均性能。
2、二叉排序树中结点各不相同,欲得到一个由大到小的结点值递减序列,你认为应当采用什么方法,便可得到要求结果,简述原因。
见过(左右换一下即可)
三、构造结果【共40分,每小题8分】
1. 给定叶结点权值:(2,3,5,6,9,11),构造哈夫曼树,并计算其带权路径长度。
练手一下,哈夫曼树。
2. 已知二叉树中序序列BDCAEF,前序序列ABCDEF,给出其对应的二叉树。
3. 已知二维数组 A[M][N]采用行序为主方式存储,每个元素占K个存储单元,已知 A[1][1](设起始下标为 1)的存储地址是 100,给出 A[ ]的存储地址算式。
见过
4. 在地址空间 0-12 的散列区中,对以下关键字序列:(Jan,Feb,Apr,May,Jun,Jul,Aug,Sep,Oct)建哈希表,设哈希函数为 H(X)=i / 2,其中i为关键字中的第一个字母在字母表中的序号,处理冲突可选用线性探测法或链地址法之一,要求构造哈希表,并求出在等概率的情况下查找成功与不成功的平均查找长度。
上手,练一下。
四、编写算法【共30分,每小题15分】
1. 编写建立二叉树算法,要求二叉树按照二叉链表方式存储。
2. 已知二叉树采用二叉链表存储,要求编写算法,完成计算出二叉树中度为0、度为1的节点数目。
// 定义二叉树节点结构体
typedef struct TreeNode {
int data;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode;
void leaf( BiTree root ){
if( root != NULL){
leaf( root->LChild);
leaf( root-> RChild);
if( root-> LChild== NUÃL && root-> RChild == NULL)
LeafCount++;
}
}
void One(BiTree root)
int Onecount = 0;
if(root != NULL){
One(root->Lchild);
One(root->Rchild);
if(root->Lchild != NULL && bt->Rchild == NULL || bt->Lchild == NULL && bt->Rchild !=NULL)
Onecount++;
return Onecount;
}
}
五、编写算法【共15分】
要求实现如下功能:
1、键盘输入N个有序整数,建立数组存储;
2、输入关键字key,完成折半查找的功能。
#include <stdio.h>
// 函数声明
int binarySearch(int arr[], int size, int key);
int main() {
int N, i, key;
int arr[100]; // 假设最多有100个元素,根据实际需要调整
// 输入N个有序整数
printf("请输入整数的个数N: ");
scanf("%d", &N);
printf("请输入%d个有序整数:\n", N);
for(i = 0; i < N; i++) {
scanf("%d", &arr[i]);
}
// 输入关键字key
printf("请输入要查找的关键字key: ");
scanf("%d", &key);
// 调用二分查找函数
int result = binarySearch(arr, N, key);
// 输出结果
if(result != -1) {
printf("元素%d在数组中的位置为:%d\n", key, result);
} else {
printf("数组中未找到元素%d\n", key);
}
return 0;
}
// 二分查找函数实现
int binarySearch(int arr[], int size, int key) {
int low = 0, high = size - 1, mid;
while(low <= high) {
mid = (low + high) / 2;
if(arr[mid] == key) {
return mid; // 找到关键字,返回其位置
} else if(arr[mid] < key) {
low = mid + 1; // 调整查找范围
} else {
high = mid - 1; // 调整查找范围
}
}
return -1; // 未找到关键字,返回-1
}
六、编写算法【共15分】
已知二叉树采用二叉链表存储,编写算法实现层次遍历二叉树。
typedef struct TreeNode {
int data;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode , *BiTree;
void LevelOrder(BiTree T){
InitQueue(Q); //初始化辅助队列
TreeNode p;
EnQueue(Q,T); //将根结点入队
while(!IsEmpty(Q)){ //队列不空则循环
DeQueue(Q,p); //队头结点出队
visit(p); //访问出队结点
if(p->lchild != NULL)
EnQueue(Q,p->lchild); //左子树不空,则左子树根结点入队
if(p->rchild != NULL)
EnQueue(Q,p->rchild); //右子树不空,则右子树根结点入队
}
}
西北大学2012年招收攻读硕士学位研究生试题
一、简答问题【共30分,每小题6分】
1. 简述数组、广义表属于线性表原因。
见过
2. 算法特性与算法时间复杂度。
①有限性②确定下③可行性④输入⑤输出
算法的时间复杂度 T(n)是对算法的时间度量,记作T(n)=O(f(n))它表示随问题规模n的增大,算法的执行时间的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度,简称时间复杂度。
3. 线性结构与非线性结构的差别。
线性结构中节点具有唯一前驱,唯一后继关系;而非线性结构中结点间的前驱、后继关系并不具有唯一性。
4. 图遍历中设置访问标志数组的作用。
见过
5. 数据类型的含义与作用。
数据类型是一组性质相同的值集合以及定义在这个值集合上的一组操作的总称。
二、方法选择【共20分,每小题10分】
1. 只想得到N个元素序列中第K个最大元素之前的部分递减有序序列(K<<N),列出2种速度快的方法名称与原因。
①堆排序,因为必趟堆排序排定一个元素,只需要进行 10 趟堆排序就可以完成前 10个排名。其他排序方法需要进行完全排序,并且由于k<<n,堆排序正适用于大量数据的排序,其复杂度为 O(nlogzn)。
②冒泡排序,冒泡排序每一趟排序会排定一个最大值,复杂度为 O(n^2)。
2. 在数轴上有 n 个彼此不交的相邻区间,每个区间下、上界都是整数,按区间位置从左到右依次编号为1-N。试问:要查找某个给定值x所在区间,你认为应选择什么方法查找最快,简述原因.
折半查找法。因为待查找序列按顺序存储,且大小有序,此时使用折半查找法比较次数少,查找速度快,平均性能小,折半查找法只适用于有序表。
三、写出要求结果【共40分,每小题8分】
1. 已知计算阿克曼递归函数定义如下:
Akm(int m,int n){
if(m==0) return(n+1);
else if(n==0) return(akm(m-1, 1));
else return(akm(m-1,akm(m, n-1)));
}
请给出执行Akm(2,1)时,递归调用顺序及执行结果。
2. 已知关键字序列为:( 75,33,52,41,12,88,66,27 )哈希表长为10,哈希函数为:H(K)=KMOD7,解决冲突用线性探测再散列法,要求构造哈希表,并求出等概率下查找成功与不成功的平均查找长度。
3. 给定权值{8,12,4,5,26,16,9},构造一颗哈夫曼树,并计算其带权路径长度。
4. 在中序线索树中,要找出x结点的前驱结点,请写出相关函数定义。
5. 已知一棵二叉树,其中序序列BDAEC,后序序列DBECA,构造该二叉树。
简单
五、编写算法
1. 要求二叉树按二叉链表存储,写建立一棵二叉树的算法。[15 分]
见过
2. 编写输出二叉树中的非叶子结点的算法。[15 分]
// 定义二叉树节点结构体
typedef struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode;
void printNonLeafNodes(TreeNode* root) {
if (root == NULL) return;
// 如果节点有子节点,则它不是叶子节点
if (root->left != NULL || root->right != NULL) {
printf("%d ", root->val);
}
// 递归遍历左子树和右子树
printNonLeafNodes(root->left);
printNonLeafNodes(root->right);
}
六、编写算法
已知有 N 个结点的无向图,采用邻接表结构存储,要求编写算法实现广度优先搜索策略遍历图中所有顶点。
广度优先搜索(Breadth-First Search, BFS)是一种用于遍历或搜索树或图的算法。对于图来说,BFS 从一个选定的源节点开始,探索所有相邻的节点,然后再从这些相邻的节点中继续向外探索,直到访问了图中所有可达的节点。在无向图中,BFS 尤其有用,因为它可以确保每个节点都被访问一次,并且访问顺序是基于节点与源节点的距离(即边的数量)的。
#define MaxVertexNum100 //图中顶点数目的最大值
typedef struct ArcNode{ //边表结点
int adjvex; //该弧所指向的顶点的位置
struct ArcNode *next; //指向下一条弧的指针
//InfoType info; //网的边权值
}ArcNode;
typedef struct Vode{ //顶点表结点
VertexType data; //顶点信息
ArcNode *first; //指向第一条依附该顶点的弧的指针
}VNode,AdjList[MaxVertexNum];
typedef struct{
AdjList vertices; //邻接表
int vexnum,arcnum; //图的顶点数和弧数
}ALGraph; //ALGraph是以邻接表存储的图类型
void BFS(Graph G,int v){ //从顶点v出发,广度优先遍历图G
visit(v); //访问初始顶点v
visited[v]=TRUE; //对v做已访问标记
Enqueue(Q,v); //顶点v入队列Q
while(!isEmpty(Q)){
DeQueue(Q,v); //顶点v出队列
for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w)) //检测v所有邻接点
if(!visited[w]){ //w为v的尚未访问的邻接顶点
visit(w); //访问顶点w
visited[w]=TRUE; //对w做已访问标记
EnQueue(Q,w); //顶点w入队列
}//if
}//while
}
西北大学2013年招收攻读硕士学位研究生试题(专业课改考,开始加入操作系统部分,专业名称844)
数据结构(共75分)
一、简答题(共15分,每小题5分)
1. 简述数据类型和抽象数据类型的含义与关系。
数据类型是一个“值”的集合和定义在此集合上的“一组操作”的总称。可看作是计算机中已经实现的数据结构。在用高级程序设计语言编写的程序中,必须对程序中出现的每个变量、常量或表达式,明确说明它们所属的数据类型。例如,C语言中的基本数据类型有:整型、字符型、实型(包括单精度型和双精度型)及枚举型。
抽象数据类型由用户定义,用以表示应用问题的数据模型。它由数据类型组成,并包括一组相关的服务(或称操作)。
2. 简述数组、广义表属于线性表原因。
线性表是 n个数据元素的有限序列,除第一个元索外,其他每一个元素有且仅有一个直接前驱。除最后一个元素外,其他每个元素有且仅有一个直接后继。
对于数组来说,很显然是符合线性表的定义的。
广义表是一个n个元素的有限序列(a1,a2,…,an),是线性表的一种推广。广义表中放宽对表元素的原子限制,容许它们具有其自身结构。它的元素可以是单个元素,也可以是一个广义表。
3. 说明在图的遍历中,设置访问标志数组的作用
见过
二、构造题(共20分,每小题5分)
1. 已知一棵二叉树,其中序序列 DBCAFGE,后序序列 DCBGFEA,构造该二叉树。
练一手
2. 快速排序方法的最好最坏情况是什么,简要分析说明理由。
要记得
快速排序执行排序的躺数取决于递归树的高度。如果每次划分都能将户列划分成为长度接近相等的子序列,则下一步将是对两个长度减半的子列进行排序,这是最理想的情况,时间复杂度0(nlogn)。最坏的情况是待排序记录已经按照其排序码从小到大排好序。这种情况下其递归树成为单支树,每次划分只得到一个比上一次少一个记录的子序。时间复杂度达到0(n^2)。
3. 已知关键字序列为:( 75,32,52,68,12,87,66,27 )哈希表长为9,哈希函数为:H(K)=KMOD7,解决冲突用线性探测再散列法,要求构造哈希表,并求出等概率下查找成功与不成功的平均查找长度。
做
4. 给定叶结点权值:{3,4,5,6,7,8,9},构造哈夫曼树,并计算其带权路径长度。
做
三、编写程序(共10分)
键盘输入n个有序值建立线性表{a,…,an},按折半查找策略实现查找给定值为 key 的元素。
将折半查找代码写上去即可
四、编写算法(共15分)
已知有N个结点的无向图,采用邻接表结构存储,要求由根开始逐层输出连通子图中所有生成树中的各条边,边输出格式为(Ki,Kj)。
#define MaxVertexNum100 //图中顶点数目的最大值
typedef struct ArcNode{ //边表结点
int adjvex; //该弧所指向的顶点的位置
struct ArcNode *next; //指向下一条弧的指针
//InfoType info; //网的边权值
}ArcNode;
typedef struct Vode{ //顶点表结点
VertexType data; //顶点信息
ArcNode *first; //指向第一条依附该顶点的弧的指针
}VNode,AdjList[MaxVertexNum];
typedef struct{
AdjList vertices; //邻接表
int vexnum,arcnum; //图的顶点数和弧数
}ALGraph; //ALGraph是以邻接表存储的图类型
void BFS(ALGraph G,int v){ //从顶点v出发,广度优先遍历图G
visit(v); //访问初始顶点v
visited[v]=TRUE; //对v做已访问标记
Enqueue(Q,v); //顶点v入队列Q
while(!isEmpty(Q)){
DeQueue(Q,v); //顶点v出队列
for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w)) //检测v所有邻接点
if(!visited[w]){ //w为v的尚未访问的邻接顶点
// visit(w); //访问顶点w
printf("(%d,%d)",GetValue(G,v),GetValue(G,v));
visited[w]=TRUE; //对w做已访问标记
EnQueue(Q,w); //顶点w入队列
}//if
}//while
}
五、编写算法(共15分)
1. 建立一颗二叉树,要求以二叉链表存储结构存储。(5分)
见过
2. 要求判断二叉树是否是一颗二叉排序树。(10分)
typedef struct BiTNode{
ElemType data; //数据域
struct BiTNode *lchild,*rchild; //左、右孩子指针
}BiTNode,*BiTree;
int pre=INT_MIN; //pre用来保存当前结点中序前驱的值
bool JudgeBST(TreeNode *t) {
if (t == nullptr) {
// 空树被认为是BST
return true;
}
// 首先递归检查左子树
bool b1 = JudgeBST(t->left);
if (!b1) {
// 如果左子树不是BST,则整棵树也不是BST
return false;
}
// 检查当前节点值是否大于中序前驱(pre)
if (pre >= t->data) {
// 如果当前节点值不大于前驱,则不满足BST的性质
return false;
}
// 更新中序前驱
pre = t->data;
// 递归检查右子树
bool b2 = JudgeBST(t->right);
return b2;
}
操作系统(共75分)
一、简述下列概念的区别与联系。(共15分,每小题3分)
1. 分时系统与实时系统
分时系统与实时系统作为两种不同类型的操作系统,在多个方面存在显著的区别,同时它们之间也存在一定的联系。以下是详细的对比和说明:
区别(答出两三点即可)
-
系统目标和应用场景
- 分时系统:主要目标是为多个用户提供一种通用性很强的系统,允许多个用户同时通过终端以交互的方式使用计算机,共享资源。这种系统广泛应用于科学计算、教育、商业等领域。
- 实时系统:目标是计算机能够及时响应外部事件的请求,并在规定的时间内完成对该事件的处理。它主要用于对时间要求极高的场合,如工业控制、航空航天、军事指挥等。
-
响应时间要求
- 分时系统:对响应时间虽有要求,但一般来说,响应时间由人所能承受的等待时间来确定,即保证用户的请求能在较短时间内得到响应,但不追求极短的响应时间。
- 实时系统:对响应时间要求很高,一般由控制系统或信息处理系统所能接受的延迟时间来决定。对于硬实时系统,如果不能满足任务的截止时间要求,可能会导致系统失败或造成严重后果。
-
交互性
- 分时系统:具有较强的交互能力,用户可以通过终端与系统进行广泛的人机对话,进行数据处理和资源共享。
- 实时系统:虽然也具有一定的交互性,但相较于分时系统,其交互能力略差。实时系统更注重于及时响应和处理外部事件,而不是提供强大的交互功能。
-
可靠性要求
- 分时系统:要求系统可靠,但实时系统对可靠性的要求更高。因为实时系统一旦出现故障,可能会导致严重的后果,如生产事故、设备损坏等。
- 实时系统:需要采用多级容错措施来保障系统的安全及数据的安全,确保在极端情况下仍能正常工作。
-
任务特性
- 分时系统:主要处理的是一般性的计算任务和数据处理任务,任务之间没有明显的截止时间要求。
- 实时系统:处理的任务往往具有实时性要求,任务可以按照执行时是否成周期性变化分为周期性实时任务和非周期性实时任务;按照对截止时间的要求分为硬实时任务和软实时任务。
联系
尽管分时系统与实时系统在多个方面存在显著的区别,但它们都是操作系统的重要类型,都旨在提高计算机系统的效率和可靠性。在某些复杂的应用场景中,可能需要将分时系统和实时系统的特点结合起来,以满足特定的需求。例如,在工业自动化控制系统中,既需要实时地响应外部事件并控制设备的运行,又需要为用户提供交互式的操作界面和数据处理功能。此时,可以采用分时与实时混合的操作系统架构来实现这些功能。
综上所述,分时系统与实时系统在系统目标、响应时间要求、交互性、可靠性要求以及任务特性等方面存在显著的区别,但它们之间也存在一定的联系和互补性。在实际应用中,需要根据具体的需求和场景来选择合适的操作系统类型。
2. 首次适应算法与最佳适应算法
首次适应算法:该算法从空闲分区链首开始查找,直至找到一个能满是其大小要求的空闲分区为止:算法倾向于使用内存中低地址部分的空闲区,保留了高地址部分的大空闲区;低地址部分不断被划分,留下许多难以利用、很小的空闲区,而每次查找又都从低地址部分开始,会增加查找的开销。
最佳适应算法:该算法总是把既能满足要求,又是最小的空闲分区分配给作业:为了加速查找,该算法要求将所有的空闲区按其大小排序;因为每次分配后剩余的空间一定是最小的,在存储器中将留下许多难以利用的小空闲区;同时每次分配后必须重新排序,这也带来了一定的开销。
3. 用户级线程与内核支持线程
用户级线程是 OS 内核可感知的,而用户级线程是 OS 内核不可感知的:用户级线程的创建、撤销和调度不需要 OS内核的支持,是在语言这一级处理的;
而内核支持线程的创建、撤销和调度都需要OS内核提供支持,而且与进程的创建、撤销与调度是大致相同的;
用户级线程执行系统调度命令时将导致其所属进程被中断,而内核支持线程执行系统调用指令时,只导致该线程被中断;
在只有用户级线程的系统内,CPU调度还是以进程为单位,处于运行状态的进程中的多个线程,由用户程序控制线程的轮换运行;
在有内核支持线程的系统内,CPU调度则以线程为单位,由OS的线程调度程序负责线程的调度,用户级线程的程序实体时运行在用户态下的程序,而内核支持线程的程序实体则是可以运行在任何状态下的程序。
4. 虚拟设备与 SPOOLing 系统
虚拟设备:通过虚拟技术将一台独占设备虚拟成多台逻辑设备,供多个用户进程同时使用,通常把这种经过虚拟的设备称为虚拟设备。
SPOOLING 系统:由预输入程序,缓输出程序、并管理程序、预输入、缓输出表、输入井,输出井组成;提高了 IO 的速度,利用输入输出井模拟成脱机输入输出,缓和了CPU和IO设备速度不匹配的矛盾;将独占设备改造为共享设备;实现了虚拟设备功能;多个进程同时使用一台独占设备虚拟成了多态设备。
5. 文件的逻辑组织和物理组织
文件系统的主要任务之一就是在逻辑文件结构和相应的物理文件结构之间建立映射关系,实现二者之间的转换。
逻辑结构:指一个文件在用户面前所呈现的形式。
逻辑结构有两种形式:①记录式文件(有结构式文件).②字符流式文件(无结构式文件),也称流式文件。
物理结构:指文件在文件存储器上的存储形式。
物理结构的形式:①连续文件结构②串联文件结构③索引文件结构④散列文件结构。
二、简答题(共30分,每小题6分)
1. 作业调度和进程调度各自的主要功能是什么?
作业调度:高级调度又称作业调度,作业就是用户程序及其所需的数据和命令的集合,作业管理就是对作业的执行情况进行系统管理的程序的集合。作业调度程序的主要功能是审查系统是否能满足用户作业的资源要求以及按照一定的算法来选取作业。
进程调度:低级调度又称进程调度,其主要功能是根据一定的算法将cpu分派给就绪队列中的一个进程。进程调度是操作系统中最基本的一种调度,其调度策略的优劣直接影响整个系统的性能。
2. 什么是分页?什么是分段?者主要有何区别?
分页:把程序中逻辑地址分成大小相等的许多页,把主存储器进行分块,块的大小与页面大小一致,块是进行主存空间分配的物理单位。这样,就可把作业信息按页存放到块中。
分段:作业的地址空间被划分为若干个段,每个段是一组完整的逻辑信息每个段都有自己的段号,都是从零开始编址的一段连续的地址空间,各段长度是不等的。
区别:
- 页是信息的物理单位,分页是出于系统管理的需要,而段是信息的逻辑单位,分段是出于用户应用的需要:一条指令或一个操作数可能会跨越两个页的分界处,而不会跨越两个段的分界处;
- 页定长,而段不定长;
- 页的地址空间是一维的,分段的地址空间是二维的;
- 页的大小固定不变由系统决定,段的大小不固定,是由其完成的功能决定的;由于段是信息的逻辑单位,因此便于存贮保护和信息的共享。
3. 何谓死锁?试说明银行家算法避免死锁的原理。
死锁的定义:如果一组进程中的每一个进程都在等待仅出该组进程中的其他进程才能引发的事件,那么该组进程就是死锁的。
银行家算法避免死锁原理:银行家算法在系统运行过程中对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若分配后系统可能发生死锁,则不分配,否则子以分配。因此他能避免死锁的发生。
4. 为什么要引入设备独立性?如何实现设备独立性?
设备独立性:为了提高操作系统的可适应性和可扩展性,在现代操作中都毫无例外地实现了设备独立性,也称为设备无关性。有设备分配时的灵活性、易于实现 I/O 重定向的好处。
为了实现设备的独立性,应引入逻辑设备和物理设备两个概念。在应用程序中,使用逻辑设备名称来请求使用某类设备;而系统执行时,是使用物理设备名称。鉴于驱动程序是一个与硬件(或设备)紧密相关的软件,必须在驱动程序之上设置,层软件,称为设备独立性软件,以执行所有设备的公有操作、完成逻辑设备名到物理设备名的转换(为此应设置一张逻辑设备表)并向用户层(或文件层)软件提供统一接口,从而实现设备的独立性。
5. 什么是Unix 系统中的软中断?它与硬中断有什么不同之处?
软中断:
(1)编程异常通常叫做软中断.
(2)软中断是通讯进程之间用来模拟硬中断的 一种信号通讯方式。
(3)中断源发中断请求或软中断信号后,CPU或接收进程在适当的时机自动进行中断处理或完成软中断信号对应的功能
(4)软中断是软件实现的中断,也就是程序运行时其他程序对它的中断;而硬中断是硬件实现的中断,是程序运行时设备对它的中断。
三、综合题(共30分,每小题10分)
1. 在现代操作系统中,一个进程从生到灭主要经历哪几个状态?画出进程状态迁移图,简述产生状态迁移的原因,分析说明如何实现这些状态迁移。
画
2. (1)假如你是一个操作系统的设计者,承担慢速字符设备管理任务。该操作系统要求;用户使用慢速字符设备和使用普通文件完全一样方便简捷。请问你在设计中至少要解决哪些问题?(2)文件系统性能改善主要有哪些方法?在 Unix系统中还采取了哪些提高磁盘IO速度的方法?试分别加以简单的说明。
(1)
A、确定一个好的顺序来执行 I/O 请求使进程之间公平地共享设备访问,减少 I/O 完成所需要地平均等待时间。
B、使用缓存技术。
C、引入设备独立性提高设备分配地灵活性和设备地利用率。
D、引入 SPOOLING 技术缓和 CPU 高速性与 I/0 设备低速性地矛盾。
(2)方法:
A、选择合适的目录结构
B、选择合适的文件共享方式
C、选择合适的文件分配方式。
D、合理管理文件存储器空间。
UNIX:采用了文件名和文件描述信息分开的方法。UNIX的文件目录结构包括文件名和索引节点指针。其中索引节点指针是指向包含文件主标识符、文件类型、文件存取权限、文件物理地址、文件长度等信息的数据结构的指针。
3. (1)在请求调页式存储管理中,什么叫快表(亦称为TLB)?为什么要引入快表?画出具有快表的地址变换机构图。(2)若一个请页式存储管理系统允许用户编程空间为32个页面(每页1kB),主存为16KB,如果用户程序有10页,且某时刻该用户的快表的内存页表如图所示:
如果分别有对以下三个虚地址:0AC5(H)、1AC5(H)、3AC5(H)处的读写操作,试计算并说明存储管理系统将如何处理这些操作。
(1)快表是一种特殊的高速缓冲存储器,内容是页表中的一部分或全部内容。在操作系统中引入快表是为了加快地址映射速度。在虚拟页式存储管理中设置了快表,作为当前进程页表的 Cache。
画图
(2)
西北大学2014年招收攻读硕士学位研究生试题
数据结构(共75分)
一、简答题(共15分,每小题5分)
1. 简述队列、广义表属于线性表原因。
见过
2. 排序稳定性的定义及证明不稳定排序的方法举例,
见过
3. 简述图的两类存储名称及结构示意。
图的两类主要存储结构是邻接矩阵和邻接表。这两种存储结构各有特点,适用于不同的场景。
1. 邻接矩阵
结构示意:
邻接矩阵是一个二维数组,用于表示图中顶点之间的连接关系。若图G有n个顶点,则邻接矩阵是一个n×n的方阵。矩阵中的元素表示顶点之间的连接状态或边的权重(对于带权图)。
- 对于无权图,如果顶点i与顶点j之间有边相连,则矩阵中对应位置(i,j)的元素为1,否则为0。
- 对于带权图(也称为网),如果顶点i与顶点j之间有边相连,则矩阵中对应位置(i,j)的元素为该边的权重;如果顶点i与顶点j之间无边相连,则矩阵中对应位置(i,j)的元素通常为一个特殊值(如无穷大或某个特定的大数),表示这两个顶点之间不直接相连。
特点:
- 直观、简单,容易实现图的遍历和查找操作。
- 但对于边数相对较少的稀疏图,邻接矩阵会浪费大量的存储空间。
2. 邻接表
结构示意:
邻接表是数组与链表相结合的存储方法。图中每个顶点用一个一维数组存储,同时,对于顶点数组中的每个顶点,还存储一个指向其邻接点的指针链表。这样,图中所有顶点的邻接点信息就分布在这些链表中。
- 对于无向图,邻接表表示的是每个顶点的边表,即该顶点连接的所有其他顶点。
- 对于有向图,邻接表表示的是每个顶点的出边表,即以该顶点为弧尾的所有弧。如果需要表示入边,可以建立逆邻接表。
特点:
- 节省存储空间,特别是对于边数较少的稀疏图。
- 但实现图的遍历和查找操作可能相对复杂一些,需要遍历链表。
综上所述,邻接矩阵和邻接表是图的两种主要存储结构,它们各有优缺点,适用于不同的场景和需求。在实际应用中,可以根据图的稀疏性、操作需求等因素选择合适的存储结构。
二、写出要求结果(共20分,每小题5分)
1. 设哈希表长度为11,哈希函数H(K)(K 的第一字母在字母表中的 序号)MOD11,若输入顺序为{D,BA,TNM,CI,I,K,X,TA},处理冲突方法为线性探测再散列或链地址法,要求构造哈希表,并求出等概率情况下查找成功与不成功的平均查找长度。
上手
2. 设有 5000个无序元素,仅要求找出前10个最小元素,在下列排序方法(归并排序、冒泡排序、快速排序、堆排序、插入排序)中哪些方法快,为什么?
对于需要从5000个无序元素中找出前10个最小元素的问题,堆排序是最佳选择,因为它能高效地维护一个最小堆并依次提取最小的元素,而不需要对整个数组进行排序。快速排序虽然理论上可以通过快速选择算法来优化,但在实现复杂度和稳定性上可能不如堆排序直接和可靠。其他排序方法(归并排序、冒泡排序、插入排序)在此场景下相对较慢。
3. 已知一颗二叉树,其中序序列 DBCAFGE,前序列序列 ABDCEFG,构造该二叉树。
见过
4. 用于通信的电文出8个字母 a,b,c,d,e,f,g,h.组成,各字母在电文中出现的频率分别为 5,25,3,6,10,11,36,4。试为这8个字母设计哈夫曼编码,并计算给出该电文编码的总长度(WPL带权路径长度)。
练手
三、编写算法(共10分)
已知二叉树采用二叉链表结构存放要求统计二又树中度为1结点个数和度为2的结点个数。
typedef struct BiTNode{
ElemType data; //数据域
struct BiTNode *lchild,*rchild; //左、右孩子指针
}BiTNode,*BiTree;
// 辅助函数:统计节点数
void countNodes(TreeNode* root, int *degree1, int *degree2) {
if (root == NULL) {
return;
}
// 检查当前节点的子节点数量
if (root->left != NULL && root->right == NULL) {
// 度为1,只有左子节点
(*degree1)++;
} else if (root->left != NULL && root->right != NULL) {
// 度为2,有两个子节点
(*degree2)++;
}
// 如果只有右子节点或者没有子节点,则不需要增加任何计数
// 递归遍历左子树和右子树
countNodes(root->left, degree1, degree2);
countNodes(root->right, degree1, degree2);
}
四、编写算法(共15分)
1. 键盘输入一组非零的整数序列,最后输入零为结束标志,要求根据输入建立一棵二叉排序树算法,采用二叉链表方式存放。(10分)
#include <stdio.h>
#include <stdlib.h>
// 定义二叉树节点
typedef struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode;
// 插入函数
TreeNode* insert(TreeNode* root, int val) {
if (root == NULL) {
root = (TreeNode*)malloc(sizeof(TreeNode));
root->val = val;
root->left = root->right = NULL;
} else if (val < root->val) {
root->left = insert(root->left, val);
} else {
root->right = insert(root->right, val);
}
return root;
}
// 中序遍历函数
void inorderTraversal(TreeNode* root) {
if (root != NULL) {
inorderTraversal(root->left);
printf("%d ", root->val);
inorderTraversal(root->right);
}
}
// 主函数
int main() {
TreeNode* root = NULL;
int val;
printf("请输入非零整数(输入0结束):\n");
while (scanf("%d", &val) && val != 0) {
root = insert(root, val);
}
printf("二叉排序树的中序遍历结果为:\n");
inorderTraversal(root);
printf("\n");
// 注意:这里未实现释放内存的代码,实际使用中应适当管理内存
return 0;
}
2. 给出按由大到小顺序输出此二叉排序树中结点值的算法。(5分)
中序遍历一下存到一个数组里面,然后反向输出数组。
操作系统(共75分)
一、简答如下问题(共30分,每小题5分)
1. 为什么要引入进程概念?进程与程序、进程与线程有何联系与区别?
引入进程的主要目的是为了使程序能独立运行,同时也能实现多个程序同时运行。在引入进程后,多个程序可以同时处于活动状态,它们共享CPU和内存等资源,从而提高了系统的利用率和并发性。此外,引入进程还可以实现程序的模块化设计,使得程序的修改和调试更加方便。
程序:就是一组指令的集合,比如你写的代码文件(.c, .py, .java等)。它本身不运行,只是静静地躺在那里,等待被执行。
进程:当程序被操作系统加载到内存中,并为其分配了资源(如CPU时间、内存空间等),这个程序就变成了进程。进程是程序执行的一个实例,是动态的,有生命周期,可以执行、等待、挂起或终止。
线程:线程是进程中的一个实体,是CPU调度和分派的基本单位。一个进程可以拥有多个线程,这些线程共享进程的资源(如内存空间、文件句柄等),但每个线程都有自己独立的执行路径和程序计数器。线程之间可以并发执行,提高程序的执行效率。
联系:
- 程序是线程的源头,线程是进程的一部分,进程是程序运行的结果。
- 它们都是实现并发执行的手段,但粒度不同:程序最粗,进程次之,线程最细。
区别:
- 程序是静态的,不占用系统资源;进程和线程是动态的,占用系统资源。
- 进程是资源分配的基本单位,每个进程都有独立的内存空间;线程是CPU调度的基本单位,多个线程共享进程的内存空间。
- 创建一个进程的开销比创建一个线程的开销大,因为进程需要分配独立的内存空间等资源。
- 进程之间通信相对复杂,需要通过操作系统提供的机制(如管道、消息队列等);线程之间通信相对简单,因为它们共享进程的内存空间。
2. 进程调度的功能是什么?调度算法主要有哪些?UNIX 系统采用什么调度算法?
进程调度的功能主要是:分配CPU给就绪进程,确保系统资源高效利用,提高系统吞吐量和用户响应速度,同时处理进程状态转换,维护并发执行环境,确保系统稳定运行。
调度算法主要有以下几种:
- 先来先服务(FCFS):按进程到达顺序进行调度。
- 时间片轮转(RR):进程轮流占用CPU时间片。
- 短作业优先(SJF):优先调度估计运行时间最短的进程。
- 优先级调度:根据进程的优先级分配CPU资源。
UNIX系统采用多级反馈队列调度算法,多级反馈队列调度算法是一种根据先来先服务原则给就绪队列排序,为就绪队列赋予不同的优先级数,不同的时间片,按照优先级抢占CPU 的调度算法。
3. 给出两个进程死锁的例子,分析产生进程死锁的原因,描述避免死锁的方法。
例子一:打印机与扫描仪共享
假设有两个进程P1(文档处理)和P2(图像处理),它们共享一台打印机(R1)和一台扫描仪(R2)。进程P1当前占用打印机R1并需要扫描仪R2来扫描新文档;同时,进程P2占用扫描仪R2并需要打印机R1来打印处理后的图像。如果两个进程都不愿释放它们当前占用的资源去等待另一个资源变得可用,那么它们就会陷入死锁状态。
原因分析:
- 资源分配不均:系统未能合理分配资源,导致两个进程都持有一个资源并等待对方释放的资源。
- 循环等待:进程间形成了一个资源的循环等待链(P1等待R2,R2被P2占用;P2等待R1,R1被P1占用)。
例子二:数据库锁竞争
在数据库管理系统中,有两个事务T1和T2。事务T1锁定了一个数据表A(R1)以进行更新,并尝试锁定另一个数据表B(R2)来完成其操作。同时,事务T2已经锁定了数据表B(R2)并尝试锁定数据表A(R1)来执行其操作。如果两个事务都不愿释放它们已持有的锁去等待对方释放锁,那么它们就会陷入死锁。
原因分析:
- 锁的顺序不一致:不同事务尝试以不同的顺序获取相同的锁,导致循环等待的发生。
- 并发控制不当:数据库系统未能有效管理事务间的锁竞争,未能及时检测到并避免潜在的死锁情况。
这两个例子都展示了资源分配不当和进程(或事务)间推进顺序不合理如何导致死锁的发生。在实际应用中,通过合理的资源分配策略、事务设计以及并发控制机制,可以有效地避免或减少死锁的发生。
银行家算法 思想(避免死锁):在进程提出资源申请时,先预判此次分配是否会导致系统进入不安全状态。如果会进入不安全状态,就暂时不答应这次请求,让该进程先阻塞等待。
4. 存储管理中,分区、分页、分段方法的主要区别是什么?它们各自有何优缺点?请给出两种能够把他们结合起来使用的例子。
存储管理中,分区、分页、分段方法的主要区别如下:
- 分区:将内存划分为固定大小的区域,每个程序占用一个或多个区域,但大小不能变,可能导致内存浪费。
- 分页:将内存划分为固定大小的页面,进程也相应地被划分为页,提高了内存利用率,但页面大小固定,可能造成外部碎片。
- 分段:根据程序的自然分界划分内存区域,每段大小可不同,提高了编程的灵活性和内存利用率,适合处理动态变化的数据。
存储管理中的分区、分页、分段方法各有优缺点,简述如下:
-
分区:
- 优点:管理简单,每个程序占用独立区域,互不干扰。
- 缺点:灵活性差,内存利用率不高,特别是当程序大小与分区不匹配时易造成浪费。
-
分页:
- 优点:提高了内存利用率,减少了外部碎片,便于实现虚拟内存技术。
- 缺点:需要额外的硬件支持,如页表和地址转换机制,增加了系统复杂性和开销。
-
分段:
- 优点:灵活性高,段的大小可以动态变化,适应不同程序的需求,便于共享和保护。
- 缺点:容易产生内部碎片,且由于段长度不一,管理开销较大,对内存利用率有一定影响。
5. 进程调度
6. 磁盘调度
磁道很简单,自己做。
二、综合题(共45分,每小题15分)
1. pv操作
讲过,自己做。
2. 分页存储管理
2)
如果没有找到匹配的页号,则需要访问内存中的页表,找到对应页表项,得到页面存放的内存块号,再将内存块号与页内偏移量拼接形成物理地址,最后,访问该物理地址对应的内存单元。因此,若快表未命中,则访问某个逻辑地址需要两次访存(注意:在找到页表项后,应同时将其存入快表,以便后面可能的再次访问。但若快表已满,则必须按照一定的算法对旧的页表项进行替换)
3)
3. 文件存储管理
技术:空闲表法,空闲链表法,位示图法,成组链接法。
(1)
windows采用空闲链表法中的空闲盘块法
分配:当用户因创建文件而请求分配空间时,系统从链首开始,依次摘下适当数目的空闲盘块分配给用户。
回收:当用户因删除文件而释放存储空间时,系统将回收的盘块依次挂在空闲盘块链的末尾。
Unix采用成组链接法。
分配:当系统为用户分配盘块时,首先检验空闲盘块号栈是否上锁,如上锁直接从栈顶取一空闲盘块号对应的空闲盘块分配给用户,然后指针下移一格。若该盘块号已是栈底,则将栈底盘块号对应的盘块的内容读入栈中,将栈底对应的盘块分配出去,再分配一相应的缓冲区,中空闲盘块数减1
回收:系统回收空闲盘块时,将回收盘块号记入空闲盘块号栈的顶部,并将空闲盘块数加 1。
(2)
系统设计人员看待文件时要考虑文件具体在存储设备中如何放置、如何组织如何实现存取等细节,这与存储介质的存储性能有关。文件在存储设备上的存储组织形式称为文件的物理组织。实现物理文件的组织方式有连续文件、串连文件、 文件、索引文件、多重索引文件。
(3)
①系统必须首先利用用户提供的交件名
②对文件目录进行查询
③找出该文件的文件控制块FCB
④对UNIX系统即要找出该文件的索引节点
⑤然后根据找到的 FCB 中所记录的文件物理地址,并根据文件物理组织方式,找出⑥文件的盘块号
⑦进而换算出交件在磁盘上的物理位置8)最后启动磁盘驱动程序,将文件读入内存
西北大学2015年招收攻读硕士学位研究生试题
数据结构(共75分)
-
(1)抽象数据类型由用户定义,用以表示应用问题的数据模型。它由构(或称操作)。抽象数据类型构造数据类型组成,并包括一组相关的服务成现代程序设计的基础。它的作用是使程序编写得易于编程、易于测试、易于修改。
[扩展]主要特点:①实现信息隐藏,把所有数据和操作分为公有和私有,可减少接口复杂性,从而减少出错机会。②实现数据封装,把数据和操作封装在一起,从语义上更加完整。③实现使用与实现相分离,使用者只能通过接口上的操作来访问数据,一旦将来修改数据结构,可以使得修改局部化,提高系统灵活性。 -
在进行算法分析时,语句总的执行次数 T(的)是关于问题规模n的函数,分析 T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度就是算法的时 间量度,记作:T(n)= Of(n)。它表示随问题规模n的增大,算法执行时间的增长率和 f(n)的增长率相同,称作算法的渐近时间复杂度简称为时间复杂度。其中f(n)是问题规模n的某个函数。
-
冒泡排序的时间代价受记录的初始排列影响。最好的情形是记录的初始排列已经按排序码的值从小到大排好序时,此算法只进行一趟冒泡,做n-1次排序码比较,不移动记录。这种情况算法最坏情形是所有记录在一开始就已经按其排序码值逆序,执行 n-1 趟冒泡,第i趟做 n-i 次排序码比较,执行 n-i 次记录交换。
构造大顶堆,自己做。
链表创建的算法
- 已知二叉树采用二叉链表存放,要求编写算法不用递归也不用栈,返回二叉树T的后序序列中的第一个结点的指针。
TreeNode* firstNode(TreeNode *t){
TreeNode*p=t;
while (p->left != NULL || p->right != NULL){
while(p->left != NULL) p=p->left;
if (p->right != NULL) p=p->right;
}
return p;
}
- 编写算法为依次输入的 n个元素构建哈希表,H(x)为哈希函数,以线性探测再散列解决冲突。
操作系统(共75分)
一、单项选择
- 在多道程序操作系统中,处理长I/O请求(如磁盘读写)的步骤简述如下:用户进程发出I/O请求后,系统将其放入队列并调度。系统分配I/O设备并启动操作,期间CPU可能执行其他任务。I/O操作完成后,设备发出中断信号,CPU响应中断并处理结果。若操作成功,用户进程被唤醒继续执行,访问I/O结果。整个过程旨在高效利用资源,提高系统响应速度。
3.不多说了吧
4. 见过
自己做
-
死锁定理是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。称此时系统处于死锁状态或系统产生了死锁。系统为死锁状态的充分条件是:当且仅当该状态的进程-资源分配图是不可完全简化的。这充分条件称为死锁定理。
-
pv操作
(1)
磁盘的盘块编号与柱面号、磁道号和扇区号之间存在着直接的对应关系。这种关系基于磁盘的物理结构和数据组织方式。具体来说,磁盘由多个盘片组成,每个盘片分为正反两面,每面都包含多个磁道,每个磁道又被划分为多个扇区。这种结构使得磁盘的存储空间可以被精确地定位和访问。
在磁盘中,盘块(也称为扇区)是最小的数据存储单位。每个盘块都有一个唯一的编号,用于标识其在磁盘上的位置。这个编号通常是通过将柱面号、磁道号和扇区号组合在一起来生成的。
(3) 11 * 8 / 7 = 95个 存放该文件的第95个逻辑记录
西北大学2016年招收攻读硕士学位研究生试题
数据结构(75分)
一、简答题
-
抽象数据类型及作用。
-
栈、队列、字符串都是限定线性表,它们各自有什么限定?
(1)栈是只允许在一端插入和删除的线性表。称为栈顶,另一端称为栈底。
(2)队列是只允许在一端删除, 在另端插入的线性表。允许删除的一端叫做队头,允许插入的一端叫做队尾。
(3)串是限定了元素为字符的线性表。
// 单链表原地逆序
void reverseList(ListNode** head) {
ListNode *prev = NULL;
ListNode *current = *head;
while (current != NULL) {
ListNode *nextTemp = current->next; // 保存当前节点的下一个节点
current->next = prev; // 将当前节点指向前一个节点,实现反转
prev = current; // 前一个节点向后移动
current = nextTemp; // 当前节点向后移动
}
*head = prev; // 新的头节点是原来的尾节点
}
2
int countOneDegree = 0; // 度为1的节点数目
// 递归函数遍历二叉树
void traverseAndCount(TreeNode* root) {
if (root == NULL) return;
// 如果左子节点存在且右子节点不存在,或者右子节点存在且左子节点不存在,则当前节点度为1
if ((root->left != NULL && root->right == NULL) || (root->left == NULL && root->right != NULL)) {
countOneDegree++;
}
// 检查叶子节点
if (root->left == NULL && root->right == NULL) {
printLeaf(root->data);
}
// 递归遍历左子树和右子树
traverseAndCount(root->left);
traverseAndCount(root->right);
}
3、
typedef struct ChildSibling {
int data;//当前结点的数据
struct ChildSibling* child;//指向孩子的指针
struct ChildSibling* sibling;//指向兄弟的指针
}TreeNode;
void level(TreeNode* t){
if(t==NULL)
return ;
Queue q;
enqueue(&q, t);
qu. push(t);
while (!isEmpty(&q)) {
TreeNode* p = dequeue(&q);
printf("%d ", p->data);
// 遍历所有孩子
for (TreeNode* child = p->child; child != NULL; child = child->sibling) {
enqueue(&q, child);
}
}
}
操作系统(75分)
一、简述下列概念联系与区别。
-
进程与线程
(1)在传统的 OS 中,进程是作为独立调度和分配的基本单位。在引入线程后,线程成为独立调度的基本单位。
(2)多个线程或进程均可以并发执行。
(3)进程可以独立拥有资源,并作为系统分配资源的一个基本单位,而线程只拥有一点必不可少的资源。
(4)资源分配给进程,同一进程的所有线程共享该进程的所有资源。
(5)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
(6)在同一进程中,线程的切换不会引起进程的切换,在 由一个进程中的线程切换到另一个进程中的线程时,将会引起进程的切换。
(7)进程切换的开销也远大于线程切换的开销。 -
静态重定位与动态重定位
静态重定位在作业执行前将用户作业存放在主存中,并完成地址转换、执行过程中无需做地址转换。故也无需地址转换机构。
动态重定位用户不能确定作业在主存中存放的位置,要借助地址转换机构在作业运行中动态计算绝对地址。
静态重定位和动态重定位的不同在于:
①静态重定位是在作业装入的时候一次完成,动态重定位是在作业执行时再实现的。
②静态重定位是软件支持的,动态重定位是硬件和软件合作实现的。
③静态重定位不能实现主存的移动,而动态重定位可以。 -
活动i结点与静态i结点
联系:无论是活动i结点还是静态i结点,它们都是文件系统中用于存储文件元数据的核心数据结构。它们共同构成了文件系统的底层基础,支持文件的创建、访问、修改和删除等操作。
区别:主要在于当前的状态和与系统的交互程度。活动i结点更可能处于被系统或进程直接访问和修改的状态,而静态i结点则相对处于较少被直接访问和修改的状态。然而,这种区分并不是绝对的,因为操作系统的缓存机制和异步I/O操作可能使得某些“静态”i结点实际上也在内存中保持活跃状态。
1、
2、
原因:①系统资源的竞争。通常系统中拥有的不可剥夺资源,其数量不足以满足多个进程运行的需要,使得进程在运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可剥夺资源的竞争才可能产生死锁,对可剥夺资源的竞争是不会引起死锁的。
②进程推进顺序非法。进程在运行过程中,请求和释放资源的顺序不当也同样会导致死锁。
方法:
1.预先静态分配法。进程在运行前一次请求完它所需要的全部组员,在它的资源未满足前,不把它投入运行。一旦运行,这些资源就一直归它所有。
2.顺序资源分配法。首先给系统中的资源编号,规定每个进程必须按编号递增的顺序请求资源,同类资源一次性申请完。
3、
缓冲技术是为了协调吞吐速度相差很大的设备之间数据传送而采用的一种技术。在现代操作系统中,几乎所有的I/O设备在与处理机交换数据时都会使用缓冲区,以缓和CPU和I/O设备速度不匹配的矛盾,提高CPU和I/O设备的并行性,减少对CPU的中断频率,从而提高系统效率。
4、
练手
1、
(1) 退票和产生新的机票是同步关系,订票和退票对于余票数量的操作是互斥关系。
(2)
2、
(1)页是信息的物理单位,分页是为了实现非连续分配,以便解决内存碎片问题,或者说分页是由于系统管理的需要。段是信息的逻辑单位,它含有一组意义相对完整的猎息,分段的目的是为了更好地实现共享,满足用户的需要。
(2)页的大小固定且由系统确定,将逻辑地址划分为页号和页内地址是由机器硬件实现的,而段的长度却不固定,决定于用户所编写的程序,通常由编译程序在对源程序进行编译时根据信息的性质来划分。
(3)分页的作业地址空间是一维的;分段的地址空间是二维的。
段页式
自己做
西北大学2017年招收攻读硕士学位研究生试题
数据结构(共75分)
一、简答题
- 简述哈希查找的基本思想,并列出哈希方法的两个关键问题。
哈希查找的基本思想是通过哈希函数将待查找的键映射为哈希表中的索引位置,以实现快速的数据访问。当发生哈希冲突时,采用特定的冲突解决策略(如开放寻址法或链地址法)来存储和查找数据。
两个关键问题:
- 哈希函数的构造:
设计一个哈希函数是哈希查找的关键,它需要满足以下要求:计算简单、分布均匀且尽可能减少哈希冲突。哈希函数的构造直接影响到哈希表的性能,包括查找速度、空间利用率等。 - 冲突解决策略:
当不同的键映射到哈希表的同一位置时,需要有一种机制来解决这种冲突。常见的冲突解决策略有开放寻址法和链地址法。开放寻址法通过某种探测序列在哈希表中寻找下一个空闲位置来存储元素;链地址法则是在每个哈希表位置维护一个链表,所有映射到该位置的元素都存储在链表中。
- 什么是排序稳定性?分别举出两个稳定和不稳定排序算法名称。
二、构造题
- 图的最小生成树有两种方法:普利姆算法和克鲁斯卡尔算法。这两种算法分别适合求稀疏图还是稠密图的最小生成树?给出简单理由。
普利姆算法对顶点进行广撒网(也就是将一个顶点的周边都检查一遍),克鲁斯卡尔是对整理好的边进行遍历,它算法的时间复杂度主要与图的边的数量有关系。所以在图的边比较少时(也就是稀疏图时)适合用克鲁斯卡尔算法,而对于稠密图就适合普里姆算法。
- 分析快速排序的最好和最坏情况性能。如何避免最坏性能发生?
见过
三、构造结果
1、
2、
3、
四、编写算法
见过
深度搜索
孩子兄弟表示法,遍历边
操作系统(共75分)
一、简述下列概念及其关系
- 同步与互斥
同步:同步亦称直接制约关系,是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系源于它们之间的合作关系。
互斥:互斥也称间接制约关系,。当一个进程进入临界区使用临界资源时,另一个进程必须等待,当占用临界资源的进程退出临界区后,另一个进程才允许区访问此临界资源。
关系:同步是一种更为复杂的互斥,而互斥是自一种特殊的同步。
- 死锁预防与死锁避免
死锁预防:可以通过破坏产生死锁的四个必要条件之一,来预防发生死锁。
死锁避免:在系统运行过程中,对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若分配后系统可能发生死锁,则不予分配,否则予以分配。
- 分页与分段(存储管理)
分页:把主存空间划分为大小相等且固定的块,块相对较小,作为主存的基本单位。每个进程也以块为单位进行划分,进程在执行时,以块为单位逐个申请主存中的块空间。
分段:用户可以根据逻辑结构将程序分成若干段,每一段的虚拟地址空间各自都从0开始编址,因此整个作业的虚拟地址空间是二维的。类似于页式管理,段式管理要通过一个段表来进行地址变换。
- 名号目录项与索引节点
名号目录项:每一个文件有一组控制信息,其中包括文件名、文件主文件大小、访问权限、存取时间以及文件的数据存放在哪些磁盘块中等信息,这就是文件控制块也就是目录项。
索引节点: UNIX为了实施文件的共享和提高目录的检索速度,只将文件名从文件控制块信息中抽出来,其余所有的控制信息构成了文件的索引节点。索引节点是从原来的文件控制块中提取出来的,从此目录项中只有文件名和指向索引节点的指针。
- 文件的逻辑组织与物理组织
逻辑:用户对文件的观察和使用是从自身处理文件数据时所采用的组织方式来看待文件组织形式。这种从用户观点出发所见到的文件组织形式称为文件的逻辑组织。
物理:又称为文件的存储结构,是指系统将文件存储在外存上所形成的一种存储组织形式,是用户不能看见的。
二、简答题
在存储层次中层次越高,越靠近cpu,存储介质访问速度越快,价格也越高,相对应所对应配置的存储容量也越小,其中寄存器,高速缓存,主存储器和磁盘缓存均属于操作系统管辖范畴,断电后它们的信息将不复存在,而低层次的固定磁盘和可移动存储介质属于设备管理的管辖范畴,它们的存储信息将被长期保存。
3、
抖动:系统频繁进行页面置换的现象。整个系统的页面替换非常频繁,以致大部分机器时间都用在来回进行的页面调度上,只有一小部分时间用于进程的实际运算方面。
原因:由于分配给进程的页面数少于进程所需的最低页面数,导致出现接连不断的缺页中断,从而引起系统抖动。也有可能是页面置换算法选取不合适。
措施:操作系统监督每个进程的工作集,并给它分配工作集所需的内存块。
重新选择更合适的页面置换算法。
4、
首次适应:总是从表的起始端的低地址部分开始查找,当第一次找到大于或等于申请大小的空闲区时,就按所需大小分配给作业。如果分配后原空闲区还有剩余空间,就修改原存储区表项。
最佳适应:每次为作业分配主存空间时,总是把既能满足要求,又是最小的空闲区分配给作业,以免由于“大材小用”而浪费主存。为了加速查找,该算法要求将所有的空闲区按其大小以递增次序的排列。
最坏适应算法:总是挑选一个最大的空闲区分割一部分给作业使用,使剩下的部分不至于太小,仍可供分配使用。没有道理。最坏适应法空闲表登记项必须按照空闲区长度以递减顺序排列,对后进入的大作业容易出现无足够主存空间分配的情况。最佳适应法可以减少内存的浪费。每种算法都有其优缺点。
5、
方法:口令保护、加密保护、访问控制列表。口令保护和加密保护是为了防止用户文件被他人存取或窃取。访问控制列表是用于控制用户对文件的访问方式。
Unix:
a、通过存取控制机制,防止因人为因素所造成的文件不安全性
b、采取系统容错技术,防止系统部分的故障所造成的文件的不安全性。
c、建立后备系统,防止由自然系统因素造成的不安全性。
三、综合题
学过,要很熟练
程序局部性原理是指程序在执行时呈现出局部性规律,即程序在一段时间内,其执行和访问的存储空间都局限于某个区域。这种局部性又具体表现为时间局部性和空间局部性:
时间局部性:如果程序中的某条指令一旦执行,则不久之后该指令可能再次被执行;如果某数据被访问,则不久之后该数据可能再次被访问。
空间局部性:一旦程序访问了某个存储单元,则不久之后,其附近的存储单元也将被访问。
方案:
当进程要求运行时,不是将它全部装入内存,而是将一部分装入,另一部分暂时不装入,就可启动程序执行。在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序。另一方面,操作系统将内存中暂时不使用的内容换出到外存上,从而腾出空间存放将要调入内存的信息。
硬件支持:一定容量的内存和外存、中断机构、地址变换机构。
主要的数据结构:页表机制或段表机制
核心算法:页面置换算法
流程:
那个图,请求调页那个流程图
西北大学2018年招收攻读硕士学位研究生试题
数据结构
一、简答
- 如何判断某无向图是否连通?
判断图是否连通,可用DFS和BFS,如果一个图是连通的,那么从一个点开始遍历,所有的点都会遍历到即是连通图。
- 基于二叉排序树的查找有哪些优缺点?如何对其缺点改进?
优点:插入,删除操作的时间复杂度都是O(log(n))级的,即经过O(log(n))时间搜索到了需插入和删除的节点的位置,后经过O(1)级的时间就可以直接插入和删除,比有序顺序表的插入和删:除O(n)(查找O(log(n))要快。
缺点:二叉排序树的构造不止和最终节点的顺序有关,还和节点插入和删除的顺序有关,在某些情况下,树的高度可以等于节点的数量,于是查找的时间复杂度就退化成了O(n)了,相当于无序顺序表的查找。
改进:在插入和删除时对二叉排序树平衡化。
二、分析题
n*logn
三、构造结果
2、 层序遍历
3、
操作系统
一、选择题
BDDABCB
二、简答题
2、
①非剥夺:
先来先服务。优点:算法简单、对长作业有利,有利于CPU繁忙的作业。缺点:效率低、对短作业不利、不利于I/O繁忙型作业。
非剥夺短作业优先。优点:平均等待时间和平均周转时间最少。缺点:对长作业不利、未考虑作业的紧迫程度。
②剥夺:
剥夺式优先级调度算法。适用于比较严格的实时系统优点:能够更多的满足紧迫作业的要求。缺点:易发生“饥饿”现象。
时间片轮转算法。 适用于分时系统。优点:能够适用于多用户系统。缺点:若时间片过小,会造成进程频繁的切换,增加 CPU的开销。
多级反馈队列调度算法。适用于 UNIX操作系统。优点:可以兼顾多方面的系统目标
3、
过程:再磁头当前的移动方向上选择与当前磁头所在磁道距离最近的请求作为下一次服务对象。
优点:寻道性能较好,可避免“饥饿”现象
缺点:对远距离磁道一端不公平。
三、综合题
见过
西北大学2019年招收攻读硕士学位研究生试题
数据结构
一、简答
- 影响哈希查找性能的因素。
- 哈希表是否均匀
- 处理冲突的方法
- 哈希表的装填因子
- 图遍历中,设置访问标志数组的作用及设置方法。
见过
二、分析
二分查找。
在数轴上查找定值x所在区间,可使用二分查找法变种。初始化左右指针,每次取中点区间检查x是否在此区间。若在,则找到;若不在,根据x与区间边界的关系调整指针。此方法利用区间有序性,快速缩小搜索范围,时间复杂度为O(log n),适合处理大量区间的情况。
三、构造结果
四、编写算法
分析:
如果此树是空树,则一定是正则二叉树。
如果此树不是空树,则从根节点开始比较其左右子树,如果左右子树相等,则是正则二叉树。
递归终止条件是某个节点左右子树都为空或者只有一个子树。
int IsnormaTree(BitTree *bt){
if(!bt)
return 1;
if(!bt -> lchild && !bt -> rchild)
return 1;
else if(bt -> lchild && bt -> rchild){
if(IsnormalTree(bt -> lchild) && IsnormalTree(bt -> rchild))
return 1;
else
return 0;
}
else
return 0;
}
二叉排序树
BiTree SearchBST(BiTree T, KeyType key){
TreeNode *p = T->Lchild;
//如果T的左孩子为空,则查找结果,返回NULL
if(p == NULL)
return NULL;
while(p->rchild !=NULL)
p = p->rchild;
return p;
}
操作系统
一、简答题
1、
原因:
1 系统资源的竞争。通常系统中拥有的不可剥夺资源,其数量不足以满足多个进程运行的需要,使得进程在 运行过程中,会因争夺资源而陷入僵局。只有对不可剥夺资源的竞争才可能产生死锁,对可剥夺资源的竞争是不会引起死锁的。
2 进程推进顺序非法,进程在运行过程中,请求和释放资源的顺序不当同样会导致死锁。
必要条件:
方法:
①死锁的预防,即破坏产生死锁的四个必要条件之一
②死锁的避免,在系统运行过程中,对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若分配后系统可能发生死锁,则不予分配,否则予以分配
③死锁的检测与解除。
二、综合题
(1)因为逻辑单元有48位 = 1TB,所以能支持。首先要拥有存储量足够的硬盘,然后通过利用局部性原理使用虚拟存储器来实现进程的运行。
(2)页表是一种特殊的数据结构,放在系统空间的页表区,存放逻辑页与物理页帧的对应关系。每个进程都拥有一个页表,PCB表中有指针指向页表。
(3)反置页表是一种特殊的页表结构,它与传统页表的主要区别在于其组织方式和用途。传统页表为每个进程的逻辑地址空间中的每一页都设置一个表项,并按页号排序,表项中存储的是物理块号。而反置页表则是为内存中的每一个物理块(或页框)设置一个表项,并按物理块号排序,表项中存储的是使用该物理块的页号及其隶属进程的标识符。
原因:为了减少页表占用的内存空间而引入了反置页表。
(1)
数据结构:设备控制表、控制器控制表、通道控制表、系统设备表。
硬件:磁盘告诉缓存、缓冲区。
(2)
- 需要用于模拟脱机输入的磁盘的输入井和用于收容I/O设备输入的数据的输出井。
- 输入进程和输出进程
- 输入缓冲区和输出缓冲区
- 井管理程序
(3)
用户使用过程:
1 由输出进程在输出井中为之申请一个空闲磁盘块区,并将要打印的数据送入其中。
2 输出进程再为用户进程申请一个空白的用户请求打印表,并将用户的打印要求填入其中,再将表挂到打印队列上。
西北大学2020年招收攻读硕士学位研究生试题
数据结构
一、简答题
二、分析题
三、构造结果
四、编程题