2024年2月23日发(作者:)
目前刚整理了 的试题 过几天 的也会上传上去
希翼对你有匡助。。。。。。。
答案与试题是配套的 选择题没有解析 有不懂得可以在文库上 我
2022
1-5 :BCDBC 6-10:BADBA
41.该方法求得的路径不一定是最
短路径。例如,对于下图所示的带权
图,如果按照题中的原则,从A 到 C
的最短路径为 A→B →C,事实上其最
短路径为 A →D →C。
42. (1)算法的基本设计思想:定义两个指针变量p 和 q,初始时均指向头
结点的下一个结点。 P 指针沿链表挪移;当p 指针挪移到第 k 个结点时, q 指针
开始与 p 指针同步挪移;当 p 指针挪移到链表最后一个结点时, q 指针所指元素
为倒数第 k 个结点。以上过程对链表仅进行一遍扫描。
(2)算法的详细实现步骤:
①count=0,p 和 q 指向链表表头结点的下一个结点;
②若 p 为空,转⑤;
③若 count 等于 k,则 q 指向下一个结点;否则,count=count+1;
④p 指向下一个结点, 转步骤②;
⑤若 count 等于 k,则查找成功,输出该结点的 data 域的值,返回 1;返回;
查找失败,返回 0;
⑥算法结束。(3)算法实现:
typedef struct LNode{
int data;
struct LNode * link;
} * LinkList;
int SearchN(LinkList list,int k){
LinkList p,q;
int count=0; /*计数器赋初值*/
p=q=list->link; /*p 和 q 指向链表表头结点的下一个结点*/
while(p!=NULL){
if(count else q=q->link;/*q 移到下一个结点*/ p=p->link; /*p 移到下一个结点*/ } if(count 查找成功*/ return (1);}//else}//SearchN 2022 1-5 :DCDCB 6- 11 :ACBBDA 41. (1)构造的散列表如下 下标 0 1 2 3 4 5 6 7 8 9 关键字 7 14 8 11 30 18 9 (2)查找成功的平均查找长度:ASL 成功=12/7。 查找不成功的平均查找长度:ASL 不成功=18/7。 42.(1)给出算法的基本设计思想: 先将 n 个数据 x0x1…xp…xn- 1 原地逆置, 得到 xn- 1…xpxp- 1…x0,然后再将前 n-p 个和后 p 个元素分别原地逆置, 得到最终 结果:xpxp+1…xn- 1x0x1…xp- 1。 (2)算法实现: void reverse(int r[],int left,int right){ int k=left,j=right,temp; //k 等于左边界 left,j 等于右边界 right while(k temp=r[k]; r[k]=r[j]; r[j]=temp; k++;//k 右移一个位置 j--;//j 左移一个位置 } } void leftShift(int r[],int n,int p){ if(p>0&&p reverse(r,0,n-1);//将全部数据逆置 reverse(r,0,n-p-1);//将前 n-p 个元素逆置 reverse(r,n-p,n-1);//将后 p 个元素逆置 } } (3)说明算法复杂性:上述算法的时间复杂度为 O(n),空间复杂度为 O(1)。 2022 1-5 :ABBCC 6-10:DACBA 41.高分笔记 图 最后一题 42.(1)算法的基本设计思想: (5 分) 1) 比较笨的方法:将两升序序列归并排序,然后求其中位数,时间复杂度 是 O(n),空间复杂度 O(n)。 2) 高效的方法:分别求两个升序序列 A 和 B 的中位数,设为 a 和b 。 如 果 a=b,则 a 或者b 即为所求的中位数。 原因:如果将两序列归并排序,则最终序列中,排在子序列 ab 前边的元素 为先前两序列中排在 a 和 b 前边的元素;排在子序列ab 后边的元素为先前两序列 a 和 b 后边的元素。所以子序列ab 一定位于最终序列的中间,有因为 a=b,显然 a 就是中位数。 如果 a≠b(假设 a< p> 原因:同样可以用归并排序后的序列来验证,归并后排序后必然有形如… a…b…的序列浮现,中位数必然浮现在(a,b)范围内。因此可以做如下处理:舍 弃 a 所在序列A 之中比较小的一半, 同时舍弃 b 所在序列 B 之中比较大的一半。 在保留的两个升序序列中求出新的中位数 a 和b,重复上述过程, 直到两个序列 只含一个元素为止,则较小者即为所求中位数。 (2)算法实现(高效方法):(8 分) int Search(int A[], int B[], int n){ int s1,e1,mid1,s2,e2,mid2; s1=0;e1=n-1;s2=1;e2=n-1; while(s1!=e1||s2!=e2){ mid1=(s1+e1)/2; mid2=(s2+e2)/2; if(A[mid1]==B[mid2]) return A[mid1]; if(A[mid1]< p){//分别考虑奇数和偶数,保持两个子数组元素个数相等 if((s1+e1)%2==0){//若元素个数为奇数 s1=mid1;//舍弃 A 中间点以前部份且保留中间点 e2=mid2; //舍弃 B 中间点以后部份且保留中间点 }//if else{//若元素个数为偶数 s1=mid1+1;//舍弃 A 中间点以前部份且保留中间点 e2=mid2; //舍弃 B 中间点以后部份且保留中间点 }//else }//if else{ if((s1+e1)%2==0){//若元素个数为奇数个 e1=mid1;//舍弃 A 中间点以后部份且保留中间点 s2=mid2;//舍弃 B 中间点以前部份且保留中间点 }//if else {//若元素个数为偶数个 e1=mid1+1;//舍弃 A 中间点以后部份且保留中间点 s2=mid2;//舍弃 B 中间点以前部份且保留中间点 }//else }//else }//while return (A[s1]) }//search (3)上述所给算法的时间、空间复杂度分别是 O(log2n)和 O(1) 。(2 分) 因为每次总的元素个数变为原来的一半,所以有: 第一次:元素个数为 n/2=n/(21) 第二次:元素个数为 n/4=n/(22) …… …… 第 k 次:元素个数为 n/(2k) 最后元素个数为 2 则有 n/(2k)=2 解得 k= log2n – 1 因此:时间复杂度为 O(log2n),而空间复杂度从上述程序中可看出为 O(1)。2022 1-5 :BAABC 6-11 :CCADAD 41.高分笔记 排序 最后一题 42. (1)算法思想:顺序遍历两个链表到尾结点时,并不能保证两个链 表同时到达尾结点。这是因为两个链表的长度不同。假设一个链表比另一 个链表长 k 个结点,我们先在长链表上遍历 k 个结点,之后同步遍历两个链表。这样我们就能够保证它们同时到达最后一个结点了。由于两个链表从 第一个公共结点到链表的尾结点都是重合的。所以它们肯定同时到达第一 个公共结点。于是得到算法思路: ①遍历两个链表求的它们的长度 L1,L2; ②比较 L1,L2,找出较长的链表,并求 L=|L1-L2|; ③先遍历长链表的 L 各结点; ④同步遍历两个链表,直至找到相同结点或者链表结束。 (2)算法的C 语言代码描述 LinkList Search_ First_ Common(LinkList L1,LinkList //本算法实现线性时间内找到两个单链表的第一个公共结点 int len1=Length(L1),len2=Length(L2); LinkList longList,shortlist;//分别指向较长和较短的链表 if(len1>len2){ longList=L1->next; shortlist=L2->next; L=len1-len2;//表长之差 }//if else{ longList=L2->next; L2){ L=len2-len1;//表长之差 shortlist=L1->next;}//else While(L-- ) longList=longList->next; while(longList!=NULL){ if(longList==shortList)//同步寻觅共同结点 return longList; else{ longList=longList->next; shortlist=shortlist->next; } //else }//while return NULL; }//Search_First_Common (3)算法的时间复杂度为 O(len1+len2,) 空间复杂度为 O(1)。 2022 1-5 :DCDBA 6- 10:CCDCA 41. (1) 给出算法的基本设计思想: (4 分) 算法的策略是从前向后扫描数组元素, 标记出一个可能成为主元素的元素Num。然后重新计数, 确认Num 是否是主元素。 算法 可分为以下两步: ①选取候选的主元素:挨次扫描所给数组中的每一个整数,将第一个遇 到的整数Num 保存到 c 中记录 Num 的浮现次数为1;若遇到的下一个整 数仍 等于Num 则计数加一,否则计数减一;当计数减到0 时,将遇到的下一个整数保存到c 中,计 数重新记为 1,开始新一轮计数,即从当前位置开始重复上述过程,直到扫描彻底部数 组元素。②判断 c 中元素是否是真正的主元素:再次扫描该数组,统计c 中元素浮现的 次数,若大于n/2,则为主元素;否则,序列中不存在主元素。 (2)算法实现:(7 分) int Majority ( int A[ ], int n ) { int i, c, count=1; / / c 用来保存候选主元素,count 用来计数 c = A[0]; / / 设置 A[0]为候选主元素 for ( i=1; i if ( A[i] = = c ) count++; / / 对 A 中的候选主元素计数 else if ( count > 0) count--;/ / 处理不是候选主元素的情况 else { / / 更换候选主元素,重新计数 c = A[i]; count = 1; }//else }//for if ( count>0 ) for ( i=count=0; i if ( A[i] = = c ) count++; if ( count> n/2 ) return c; / / 确认候选主元素 else return -1; / / 不存在主元素 }//Majority 42. (1)采用顺序存储结构,数据元素按其查找概率降序罗列。(2 分) 采 用 顺 序 查 找 方 法 。 (1 分 ) 查 找 成 功 时 的 平 均 查 找 长 度 = 0.35×1+0.35 ×2+0.15×3+0.15×4=2.1。(2 分) (2) 【答案一】采用链式存储结构, 数据元素按其查找概率降序罗列, 构成单链表。 (2 分) 采用顺序查找方法。 (1 分) 查找成功时的平均查找长度=0.35×1+0.35×2+0.15 ×3+0.15×4=2.1。(2 分) 【答案二】采用二叉链表存储结构,构造二叉排序树,元素存储 方式见下图。 (2 分) 2022 1-5 :CBADC 6-11 :DDDDBC 41 .解答:考查二叉树的带权路径长度,二叉树的带权路径长度为每一个叶 子结点的深度与权值之积的总和,可以使用先序遍历或者层次遍历解决问题。 1)算法的基本设计思想: ①基于先序递归遍历的算法思想是用一个 static 变量记录 wpl,把每一个结点 的深度作为递归函数的一个参数传递, 算法步骤如下: 若该结点是叶子结点, 那 么变量wpl 加之该结点的深度与权值之积;若该结点非叶子结点, 那末若左子 树不为空,对左子树调用递归算法, 若右子树不为空,对右子树调用递归算法, 深度参数均为本结点的深度参数加一;最后返回计算出的 wpl 即可。 ②基于层次遍历的算法思想是使用队列进行层次遍历, 并记录当前的层数, 当遍历到叶子结点时, 累计 wpl;当遍历到非叶子结点时对该结点的把该结点的 子树加入队列;当某结点为该层的最后一个结点时,层数自增 1;队列空时遍历 结束,返回 wpl 2)二叉树结点的数据类型定义如下: typedef struct BiTNode{ int weight; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree; 3)算法代码如下: ①基于先序遍历的算法: intWPL(BiTreeroot){ return wpl_PreOrder(root,0); }//int intwpl_PreOrder(BiTreeroot,intdeep){ static int wpl=0;//定义一个 static 变量存储 wpl if(root->lchild==NULL&&root->lchild==NULL)//若为叶子结点,积累 wpl wpl+=deep*root->weight; if(root->lchild!=NULL)//若左子树不空,对左子树递归遍历 wpl_PreOrder(root->lchild,deep+1); if(root->rchild!=NULL)//若右子树不空,对右子树递归遍历 wpl_PreOrder(root->rchild,deep+1); return wpl; }//wpl_PreOrder ②基于层次遍历的算法: #defineMaxSize100 //设置队列的最大容量 int wpl_LevelOrder(BiTree root){ BiTree q[MaxSize]; //声明队列, end1 为头指针, end2 为尾指针 int end1, end2; //队列最多容纳MaxSize-1 个元素 end1=end2=0; //头指针指向队头元素,尾指针指向队尾的后一个元素 int wpl=0, deep=0; //初始化 wpl 和深度 BiTree lastNode; //lastNode 用来记录当前层的最后一个结点 BiTree newlastNode; //newlastNode 用来记录下一层的最后一个结点 lastNode=root; /lastNode 初始化为根节点 newlastNode=NULL; //newlastNode 初始化为空 q[end2++]=root; //根节点入队 while(end1!=end2){ //层次遍历,若队列不空则循环 BiTree t=q[end1++]; //拿出队列中的头一个元素 if(t->lchild==NULL&&t->lchild==NULL) wpl+=deep*t->weight; //若为叶子结点,统计wpl if(t->lchild!=NULL){ //若非叶子结点把左结点入队 q[end2++]=t->lchild; newlastNode=t->lchild; } //并设下一层的最后一个结点为该结点的左结点if(t->rchild!=NULL){ //处理叶节点 q[end2++]=t->rchild; newlastNode=t->rchild; }//if if(t==lastNode){//若该结点为本层最后一个结点,更新 lastNode lastNode=newlastNode; deep+=1; //层数加 1 }//if }//while return wpl; //返回 wpl }//wpl_LevelOrder 注意: 上述两个算法一个为递归的先序遍历, 一个为非递归的层次遍历,读 者应当选取自己最擅长的书写方式。 直观看去,先序遍历代码行数少,不用运用其他工 具,书写也更容易,希翼读者能掌握。 在先序遍历的算法中, static 是一个静态变量, 只在首次调用函数时声明 wpl 并赋值为 0,以后的递归调用并不会使得 wpl 为 0,具体用法请参考相关资料中的static 关键字说明,也可以在函数之外预先设 置一个全局变量, 并初始化。 无非考虑到历年真题算法答案通常都直接仅仅由一 个函数构成,所以参考答案使用 static。若对static 不熟悉的同学可以使用以下形 式的递归: int wpl_PreOrder(BiTree root,intdeep){ int lwpl, rwpl; //用于存储左子树和右子树的产生的wpl lwpl=rwpl=0; if(root->lchild==NULL&&root->lchild==NULL) //若为叶子结点, 计算当前叶子结点的wplreturn deep*root->weight; if(root->lchild!=NULL) //若左子树不空,对左子树递归遍历 lwpl=wpl_PreOrder(root->lchild,deep+1); if(root->rchild!=NULL) //若右子树不空,对右子树递归遍历 rwpl=wpl_PreOrder(root->rchild,deep+1); return lwpl+rwpl; }//wpl_PreOrder C/C++语言基础好的同学可以使用更简便的以下形式: int wpl_PreOrder(BiTree root,int deep){ if(root->lchild==NULL&&root->lchild==NULL) //若为叶子结点,积累 wpl return deep*root->weight; return(root->lchild!=NULL?wpl_PreOrder(root->lchild,deep+1):0)+ (root->rchild!=NULL?wpl_PreOrder(root->rchild,deep+1):0); }//wpl_PreOrder 这个形式只是上面方法的简化而已,本质是一样的,而这个形式代码更短,在 时间有限的 情 况 下 更 具 优 势 , 能 比 写 层 次 遍 历 的 考 生 节 约 很 多 时 间 , 所 以 读 者 应 当 在 保 证 代 码 正 确 的 情况下,尽量写一些较短 的算法,为其他题目赢得更多的时间。但是,对于基础不扎实的考生,还 是建议使用写对把握更大的方法,否则可能会得不偿失。例如在上面的代 码中,考生容易忘记三元式(x?y:z)两端的括号,若不加括号,则答案就会是错 误的。 2022 1-5 :DCCBD 6- 11 :AACBBA 41.(1) 算法思想: 定义一个大小为N 的数组,初始化为0. 在遍历链表的同时将数 组中索引值为节点的值的绝对值的元素置 1. 如果此元素已经为 1,说明此节点之前已经 有与此节点的值的绝对值相等的节点, 需将此节点删除。 (2) 节点的数据结构定义如下: typedef struct Node { Int data; Struct Node * next; }Node; (3) int a[n]; // 全局数组标志节点的绝对值的值是否浮现过 void DeleteABSEqualNode(Node * head) { memset(a,0,n); // 初始化为0 if (head == NULL) { return NULL; } Node * p = head; Node * r = head while (p != NULL) { if (a[abs(p->data)] == 1){ //如果此绝对值已经在节点值的绝对值中浮现过则 删除当前节点 r->next = p->next; delete p; p = r->next; } //if else { //否则, 将数组中对应的元素置 1,并将指针指向下一个元素 a[abs(p->data)] = 1; r = p; p = p->next; }//else } //while return head; }//DeleteABSEqualNode 只遍历一次链表,所以时间复杂度为O(n), 因为申请大小为n 的数组,所以 空间复杂度为O(n),(n 为节点绝对值的最大值)。 42. 1 邻接矩阵为: (2) 0 行 3 列的元素的含义是顶点0 到顶点3 的最短距离为2. (3) Bm 中非零元素的含义是: 假设此顶点位于i 行j 列,如果i==j,则表示到自己的距离为0;如果i≠j,则表示顶点 i 到达不了顶点j。 i 顶点


发布评论