【数据结构入门精讲 | 第四篇】考研408、企业面试表专项习题

厦门大学计算机考研分析 人工智能研究院以探索全链条大交叉新型科研模式,引领学校信息学科攀升一流,高质量服务国家/区域经济社会发展为目标,校内赋能优势学科,突出计算机视觉、模式识别、空间数据计算、社交网络分析、人工智能芯片、机器翻译等特色,发挥智能声纳、智能能源动力健康、人工智能芯片半导体制备等交叉优势,提升人工智能学科内涵,形成厦大特色的AI优势方向;PPT内容可以包括但不限于:竞赛和科研经历,实习项目经历,软件、硬件能力,毕设、课程设计、大作业中涉及到调研、自学、代码、硬件等,尽量体现自己解决实际问题的能力; 阅读详情

在上一篇中我们介绍了表的相关概念,这篇文章我们进行表的专项练习。

在这里插入图片描述

顺序表判断题

1.对于顺序存储的长度为N的线性表,删除第一个元素和插入最后一个元素的时间复杂度分别对应为O(1)和O(N)。(错)

解析:删除第一个元素需要将数组中的所有元素向前移动一位,以填补删除元素所占用的位置。因此,时间复杂度为O(N)。

void delete_first_element(int *arr, int n) {
    for (int i = 0; i < n - 1; i++) {
        arr[i] = arr[i+1];
    }
    arr[n-1] = 0;
}

插入最后一个元素只需要将新元素添加到数组的末尾即可,时间复杂度为O(1)

 for (int i = 0; i < len; i++) {
       new_arr[i] = arr[i];
      }
       new_arr[len] = element;

2.在N个结点的顺序表中访问第i(1<=i<=N)个结点和求第i(2<=i<=N)个结点直接前驱的算法时间复杂度均为O(1)。(对)

解析如下:

        printf("%d %d", arr[i - 1], arr[i - 2]);

3.顺序存储方式的优点是存储密度大,且插入、删除运算效率高。 (错)
解析:顺序存储方式存储密度大但插入删除效率低。

4.对于顺序存储的长度为N的线性表,访问结点和增加结点的时间复杂度分别对应为O(1)和O(N)。(对)
解析:在插入操作时,需要将插入位置后面的元素都向后移动,以便为新元素腾出空间

5.在用数组表示的循环队列中,front值一定小于等于rear值。(错)

顺序表选择题

1.在这里插入图片描述
选B,解析:
三角矩阵如下图

在这里插入图片描述
三对角矩阵除了第一行和最后一行是每行2个元素外,中间的每行都是三个元素。m30,30对应的元素序号为:2(第一行2个元素)+28*3+2(最后一行2个元数)=88,在数组中下标为87。

2.稀疏矩阵采用三元组存储的时候,一般需要一个行逻辑链接的顺序表,用以指出每一行的第一个非零元素在三元组中的位置。用这个顺序表的主要目的是为了_ C_。
A.更清晰表示每列元素所在位置
B.更清晰表示每行元素所在位置
C.加快算法运行效率
D.节省存储空间
解析:使用行逻辑链接的顺序表可以加快对稀疏矩阵的操作和处理速度,从而提高算法的运行效率。这个顺序表可以帮助快速访问每一行的非零元素,减少不必要的遍历和搜索操作,从而节省时间。

3.在包含 n 个数据元素的顺序表中,▁▁B▁▁ 的时间复杂度为 O(1)。
A.将 n 个元素按升序排序
B.访问第 i(1≤i≤n) 个数据元素
C.在位序 i(1≤i≤n+1) 处插入一个新结点
D.删除位序 i(1≤i≤n) 处的结点

4.已知二维数组 A 按行优先方式存储,每个元素占用 1 个存储单元。若元素 A[0][0] 的存储地址是 100,A[3][3] 的存储地址是 220,则元素 A[5][5] 的存储地址是:选D
A.301
B.295
C.306
D.300
解析:由A[0][0]和A[3][3]的存储地址可知A[3][3]是二维数组A中的第121个元素,假设二维数组A的每行有n个元素,则n x 3 + 4 = 121,n=39
所以元素 A[5][5] 的存储地址是100 + 39 * 5 + 6 -1 = 300

5.对于顺序存储的长度为N的线性表,访问结点和增加结点的时间复杂度为:C
A.O(1), O(1)
B.O(N), O(N)
C.O(1), O(N)
D.O(N), O(1)

6.若在含n个元素的顺序表中执行删除操作,设删除每个元素的概率相同,则该删除操作需移动元素的平均次数为 (n-1)/2。
解析:
要删除的个数从1~n
如果删除最后一个,则不需要移动
删除倒二个,则移动一次
删除第一个,则移动n-1次
所以一共移动(n-1)*n/2次
再除以n

在这里插入图片描述解析:可以找n+1个位置插入
如果插入到最后一个后面,则不需要移动
插入到倒二个后面,则移动一次
插入到倒三个后面,则移动二次
所以一共移动(n+1)*n/2次
再除以n+1

8.在带哨兵结点的双循环链表中,设链结点的后继指针域为next,前驱指针域为prior,指针header指向哨兵结点,则判断该链表是否为空的表达式为:header->next==header 或 header->prior==header

顺序表编程题

R6-1 线性表元素的区间删除

给定一个顺序存储的线性表,请设计一个函数删除所有值大于min而且小于max的元素。删除后表中剩余元素保持顺序存储,并且相对位置不能改变。

函数接口定义:

List Delete( List L, ElementType minD, ElementType maxD );

其中List结构定义如下:

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 保存线性表中最后一个元素在数组中的位置 */
};

L是用户传入的一个线性表,其中ElementType元素可以通过>、==、<进行比较;minD和maxD分别为待删除元素的值域的下、上界。函数Delete应将Data[]中所有值大于minD而且小于maxD的元素删除,同时保证表中剩余元素保持顺序存储,并且相对位置不变,最后返回删除后的表。

裁判测试程序样例:

#include <stdio.h>

#define MAXSIZE 20
typedef int ElementType;

typedef int Position;
typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last; /* 保存线性表中最后一个元素的位置 */
};

List ReadInput(); /* 裁判实现,细节不表。元素从下标0开始存储 */
void PrintList( List L ); /* 裁判实现,细节不表 */
List Delete( List L, ElementType minD, ElementType maxD );

int main()
{
    List L;
    ElementType minD, maxD;
    int i;

    L = ReadInput();
    scanf("%d %d", &minD, &maxD);
    L = Delete( L, minD, maxD );
    PrintList( L );

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

10
4 -8 2 12 1 5 9 3 3 10
0 4

输出样例:

4 -8 12 5 9 10 
List Delete(List L,ElementType minD,ElementType maxD)
{
	int j=0;
	
	int k=L->Last;//最后一个元素的位置
	for(int i=0;i<=k;i++)
	{
		if(L->Data[i]<=minD||L->Data[i]>=maxD)
		{
			//如果该数应该被保留,则复制到新的线性表
			L->Data[j]=L->Data[i];
			j++;
		}
		else
		{
			//如果该数应该被删除
			//将原线性表的最后一个元素复制到当前位置i,同时将原线性表的最后一个元素的索引k减1
            //相当于删除了当前元素
			L->Last--;
		}
	}
}

R7-1 数组循环左移

本题要求实现一个对数组进行循环左移的简单函数:一个数组a中存有n(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向左移m(≥0)个位置,即将a中的数据由(a0a1⋯an−1)变换为(am⋯an−1a0a1⋯am−1)(最前面的m个数循环移至最后面的m个位置)。如果还需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?

输入格式:

输入第1行给出正整数n(≤100)和整数m(≥0);第2行给出n个整数,其间以空格分隔。

输出格式:

在一行中输出循环左移m位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。

输入样例:

8 3
1 2 3 4 5 6 7 8

输出样例:

4 5 6 7 8 1 2 3
#include <stdio.h>
int main()
{
	int a,b;scanf("%d%d",&a,&b);int c[a];
	for(int i=0;i<a;i++)scanf("%d",&c[i]);
		
	int t=b%a;//对b>a的情况进行处理
    //如果左移八位,但是只有七个元素,相当于只左移了一个(取余)
	
	//如果t=1,则第一个元素要移动
	//如果t=2,则第二个元素要移动
	//将要移动的元素存储在另一个数组
	int d[a],j=0;
	for(int i=0;i<t;i++)
	{
		d[j]=c[i];
		j++;
	}
	
	//先输出不动的元素,再输出新数组中的元素
	for(int i=t;i<a;i++)
		printf("%d ",c[i]);
	for(int i=0;i<j;i++)
		printf("%d ",d[i]);
}

R7-1 最长连续递增子序列

给定一个顺序存储的线性表,请设计一个算法查找该线性表中最长的连续递增子序列。例如,(1,9,2,5,7,3,4,6,8,0)中最长的递增子序列为(3,4,6,8)。

输入格式:

输入第1行给出正整数n(≤105);第2行给出n个整数,其间以空格分隔。

输出格式:

在一行中输出第一次出现的最长连续递增子序列,数字之间用空格分隔,序列结尾不能有多余空格。

输入样例:

15
1 9 2 5 7 3 4 6 8 0 11 15 17 17 10

输出样例:

3 4 6 8
#include <stdio.h>
int main()
{
	int n;scanf("%d",&n);int a[n];for(int i=0;i<n;i++)scanf("%d",&a[i]);
	int count=1,max=1,b[n];
	b[0]=a[0];//如果没有递增子序列,则输出第一个元素
	
	for(int i=0;i<n-1;i++)
	{
		if(a[i]<a[i+1])//如果后一个大于前一个
		{
			count++;//个数递增
		if(count>max)//如果当前递增序列个数大于最大序列个数,就进行max和数组的赋值
		{
			max=count;
			for(int j=0;j<max;j++)
			{
				b[j]=a[i-j+1];
			}
		}
		}
		else
		{
			//如果后一个不会大于前一个,则连续递增子序列需要重新开始计算
			count=1;
		}
		
	}
	
	for(int i=max-1;i>0;i--)
	{
		printf("%d ",b[i]);
	}
	printf("%d",b[0]);
}

R7-2 求链式线性表的倒数第K项

给定一系列正整数,请设计一个尽可能高效的算法,查找倒数第K个位置上的数字。

输入格式:

输入首先给出一个正整数K,随后是若干非负整数,最后以一个负整数表示结尾(该负数不算在序列内,不要处理)。

输出格式:

输出倒数第K个位置上的数据。如果这个位置不存在,输出错误信息NULL。

输入样例:

4 1 2 3 4 5 6 7 8 9 0 -1

输出样例:

7
#include <stdio.h>
int main()
{
	int a;scanf("%d",&a);
	int b[1000],count=0;
	for(int i=1;;i++)
	{
		scanf("%d",&b[i]);
		if(b[i]<0)
		break;
		count++;
	}
	
	printf("%d",b[count-a+1]);
}
//a[1] a[2] a[3] a[4] a[5] a[6] a[7]
//  1    2    3    4    5    6   -1
//此时count为6
//如果输出倒数第三个
//那就是a[count-3+1]



方法二:
    #include <stdio.h>
int main()
{
	int k,n=0;
	scanf("%d",&k);
	int i,a[1000];
	for(i=1;i++;)
	{
		scanf("%d",&a[i]);
		n++;
		if(a[i]<0)
		break;
	}
	
	a[0]=k;
	

printf("%d",a[n-k+1]);
}

链表判断题

1.链表是一种随机存取的存储结构。(错)
解析:链表的顺序访问是通过从头节点开始,依次遍历链表的节点来实现的,即链式存储结构。
数组是一种随机存取的存储结构,可以通过索引直接访问数组中的任意元素。

2.线性表L如果需要频繁地进行不同下标元素的插入、删除操作,此时选择顺序存储结构更好。(错)
解析:由于链式存储结构在插入和删除操作时不需要移动大量元素,只需修改指针连接,因此更适合频繁变动的情况。

3.在具有N个结点的单链表中,访问结点和增加结点的时间复杂度分别对应为O(1)和O(N)。(错)
解析:访问结点的时间复杂度为O(N),增加结点的时间复杂度为O(1)。

4.若用链表来表示一个线性表,则表中元素的地址一定是连续的。(错)
解析:链表中的节点可以在内存中的任意位置,它们通过指针连接起来形成链表结构。
使用数组来表示线性表时,数组中的元素是连续存储的。

5.将N个数据按照从小到大顺序组织存放在一个单向链表中。如果采用二分查找,那么查找的平均时间复杂度是O(logN)。(错)
如果是存放在数组中,则是对的。但由于在链表中,所以不会是logn

6.对于单循环链表,表空的表达式为header->next==header。(对)

链表选择题

1.假设某个带头结点的单链表的头指针为head,则判定该表为空表的条件是( D )
A.head= =NULL
B.head!=NULL
C.head->next= =head
D.head->next= =NULL
解析:在带头结点的单链表中,如果链表为空表,头结点的下一个指针head->next指向的也应为空。

在这里插入图片描述
选A,解析:“链接地址”是指结点next所指的内存地址。

在这里插入图片描述

3.在具有N个结点的单链表中,实现下列哪个操作,其算法的时间复杂度是O(N)? 选B
A.在地址为p的结点之后插入一个结点
B.遍历链表和求链表的第i个结点
C.删除地址为p的结点的后继结点
D.删除开始结点
解析:遍历链表需要按顺序访问每个结点,因此时间复杂度为O(N)。而求链表的第i个结点也需要遍历i个结点,所以同样具有O(N)的时间复杂度。
选项 A. 在地址为p的结点之后插入一个结点 的操作只需要修改指针连接,时间复杂度为O(1)。 选项 C. 删除地址为p的结点的后继结点 的操作也只需要修改指针连接,时间复杂度为O(1)。 选项 D. 删除开始结点的操作只需要修改头指针的指向,时间复杂度为O(1)。

在这里插入图片描述

选C,解析:要实现两个多项式的乘法,需要让一个多项式的每一项乘以另外一个多项式的每一项,因此这个题目的时间复杂度只跟非零项的个数有关,与最高项的指数无关。

5.已知指针ha和hb分别是两个单链表的头指针,下列算法将这两个链表首尾相连在一起,并形成一个循环链表(即ha的最后一个结点链接hb的第一个结点,hb的最后一个结点指向ha),返回ha作为该循环链表的头指针。请将该算法补充完整。

typedef struct node{
ElemType data;
    struct node *next;
}LNode;
LNode *merge(LNode *ha, LNode *hb) {
LNode *p=ha;
     if (ha==NULL || hb==NULL) {
cout<<”one or two link lists are empty!”<<endl;
          return NULL;
     }
     while ( p->next!=NULL )
           p=p->next;
     p->next=hb;
     while ( p->next!=NULL )
           p=p->next;
           _____A_____
}

A.p->next=ha; return ha;
B.ha=p->next; return p;
C.p->next=ha; return p;
D.ha=p->next; return ha;
选A,解析:在补充完整算法的过程中,首先让p指针遍历到链表ha的末尾,然后将ha的末尾指针指向hb的头部,形成循环链表。最后返回ha作为该循环链表的头指针。

6.对于一非空的循环单链表,h和p分别指向链表的头、尾结点,则有:选C
A.p->next == NULL
B. p == h
C.p->next == h
D.p == NULL
解析:对于非空的循环单链表,尾结点的指针域应该指向头结点,即p->next == h

7.双链表的结点类型定义如下:
typedef struct node *link; //双链表结点指针类型
typedef struct node {// 双链表结点类型
ListItem element;//表元素
link left,//链表左结点指针
right;//链表右结点指针
}Node;
在双向链表存储结构中,删除 p 所指的结点,相应语句为:( )
A.p->right->left=p; p->right=p->right->right;
B.p->right=p->left->left; p->left=p->right->right;
C.p->left->right=p->right; p->right->left=p->left;
D.p->left=p->left->left; p->left->right=p;
解析:选C,画图即可
left-A-right left-p-right left-b-right

8.链表具有的特点是(D)。
A.可随机访问任意一个元素
B.要事先估计存储空间
C.插入删除需要移动元素
D.所需空间与线性表长度成正比
解析:A,不可。B,不需要。C,只要移动指针。D,对。

9.在单链表指针为p的结点之后插入指针为s的结点,正确的操作是__B__。
A.p->next=s;s->next=p->next
B.s->next=p->next;p->next=s
C.P->next=s;p->next=s->next
D.P->next=s->next;p->next=s

10.在需要经常查找结点的前驱与后继的场合中,使用( B )比较合适。
A.单链表 B.双链表 C.顺序表 D.循环链表

11.用链接方式存储的队列,在进行插入运算时( D ).
A. 仅修改头指针 B. 头、尾指针都要修改
C. 仅修改尾指针 D.头、尾指针可能都要修改

12.下列关于静态链表的说法错误的是( C )。
A、多条静态链表可共用一个数组空间
B、在数组空间中,静态链表中的元素可以随机存放
C、静态链表可以无限扩充
D、静态链表的指针域也称为游标,存放下一元素在数组中的下标

链表填空题

(pre)p(next)   与   (pre)q(next)是双向指向的
要在两者之间插入新的节点x,怎么操作?
解析:
x->pre=p
x->next=p->next
p->next->pre=x
p->next=x

下列代码的功能是返回带头结点的单链表L的逆转链表。

List Reverse( List L )
{
    Position Old_head, New_head, Temp;
    New_head = NULL;
    Old_head = L->Next;

    while ( Old_head )  {
        Temp = Old_head->Next;
        
                ;//Old_head->Next = New_head
        New_head = Old_head;  
        Old_head = Temp; 
    }
    
                ;//L->Next = New_head
    return L;
}

解析:代码注释如下

List Reverse( List L )
{
    Position Old_head, New_head, Temp;
    New_head = NULL;  // 初始化新链表头节点指针为NULL
    Old_head = L->Next;  // 保存原链表头节点的下一个节点

    while ( Old_head )  {
        Temp = Old_head->Next;  // 保存当前节点的下一个节点
        
        Old_head->Next = New_head;  // 将当前节点的Next指针指向新链表的头节点
        New_head = Old_head;  // 更新新链表的头节点为当前节点(将当前节点插入到新链表的头部)
        Old_head = Temp;  // 将当前节点移动到下一个节点
    }
    
    L->Next = New_head;  // 将原链表的头节点指向新链表的头节点
    return L;  // 返回反转后的链表头节点指针
}

链表函数题

R6-1 单链表分段逆转

给定一个带头结点的单链表和一个整数K,要求你将链表中的每K个结点做一次逆转。例如给定单链表 1→2→3→4→5→6 和 K=3,你需要将链表改造成 3→2→1→6→5→4;如果 K=4,则应该得到 4→3→2→1→5→6。

函数接口定义:

void K_Reverse( List L, int K );

其中List结构定义如下:

typedef struct Node *PtrToNode;
struct Node {
    ElementType Data; /* 存储结点数据 */
    PtrToNode   Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */

L是给定的带头结点的单链表,K是每段的长度。函数K_Reverse应将L中的结点按要求分段逆转。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;

typedef struct Node *PtrToNode;
struct Node {
    ElementType Data; /* 存储结点数据 */
    PtrToNode   Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */

List ReadInput(); /* 裁判实现,细节不表 */
void PrintList( List L ); /* 裁判实现,细节不表 */
void K_Reverse( List L, int K );

int main()
{
    List L;
    int K;

    L = ReadInput();
    scanf("%d", &K);
    K_Reverse( L, K );
    PrintList( L );

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

6
1 2 3 4 5 6
4

输出样例:

4 3 2 1 5 6

代码如下:

void K_Reverse(List L,int K)
{
	List H=L;
	PtrToNode p,q,w,t;//定义指针
	int num;//用于计数
	while(H)//遍历整个链表
	{
		num=0;
		p=H;//p指向当前待翻转的第一个节点
		
		//找到需要翻转的K个节点
		while(num<K&&p->Next)
		{
			num++;
			p=p->Next;
		}
		
		if(num<K)
		return;//如果不足K个节点,则退出循环
		else
		{
			//对这K个节点进行翻转操作
			
            t=H->Next;//t指向待翻转区间的前驱节点
			w=p->Next;//w指向待翻转区间的后继节点
			p->Next=null;//将待翻转区间的后继节点置为Null,便于后面插入节点
			
			//将待翻转的每个节点插入到头部节点之后
			p=H->Next;
			
			while(p)
			{
				q=p;//q指向当前待插入的节点
				p=p->Next;
				q->Next=H->Next;//将该节点插入到头部节点之后
				H->Next=q;
			}
			
			//连接待翻转区间的前驱节点和后继节点
			t->Next=w;
			
			//将指针H指向下一个待翻转区间的头部节点
			H=t;
			
		}
	}
}

链表编程题

R7-1 喊山

喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂—喂喂喂……”的呼唤。呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的“讯号”,达到声讯传递交流的目的。原来它是彝族先民用来求援呼救的“讯号”,慢慢地人们在生活实践中发现了它的实用价值,便把它作为一种交流工具世代传袭使用。

一个山头呼喊的声音可以被临近的山头同时听到。题目假设每个山头最多有两个能听到它的临近山头。给定任意一个发出原始信号的山头,本题请你找出这个信号最远能传达到的地方。

输入格式:

输入第一行给出3个正整数n、m和k,其中n(≤10000)是总的山头数(于是假设每个山头从1到n编号)。接下来的m行,每行给出2个不超过n的正整数,数字间用空格分开,分别代表可以听到彼此的两个山头的编号。这里保证每一对山头只被输入一次,不会有重复的关系输入。最后一行给出k(≤10)个不超过n的正整数,数字间用空格分开,代表需要查询的山头的编号。

输出格式:

依次对于输入中的每个被查询的山头,在一行中输出其发出的呼喊能够连锁传达到的最远的那个山头。注意:被输出的首先必须是被查询的个山头能连锁传到的。若这样的山头不只一个,则输出编号最小的那个。若此山头的呼喊无法传到任何其他山头,则输出0。

输入样例:

7 5 4
1 2
2 3
3 1
4 5
5 6
1 4 5 7

输出样例:

2
6
4
0
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define PI 3.1415926535897932
#define E 2.718281828459045
#define INF 0x3f3f3f3f  // 无穷大的定义,用于表示不可达的距离
#define mod 123456789   // 取模的常数
#define N 70            // 节点的最大数量
typedef long long ll;   // 定义长整型数据类型
const int M=1005;       // 定义图的最大边数
int n,m;                // 节点数和边数
int cnt;                // 素数个数
int sx,sy,sz;           // 起点坐标
int mp[M][12];          // 存储图的邻接矩阵
int pa[M],rankk[M];     // 并查集使用的数组
int head[M*6],vis[M*10]; // 链表头和访问标记数组
double dis[M][10];      // 距离数组
ll prime[M*1000];       // 存储素数的数组
bool isprime[M*1000];   // 是否为素数的标记数组
int lowcost[M],closet[M];// 最小生成树算法中的数组
char st1[5050],st2[5050];// 字符串数组
int len[M*6];           // 每个节点对应的字符串长度数组
typedef pair<int ,int> ac; // 存储节点和距离的pair类型
vector<int> g[M*10];    // 图的邻接表表示
int dp[2005][2005];     // 动态规划数组
bool has[10000];        // 哈希表判重数组
int month[13]= {0,31,59,90,120,151,181,212,243,273,304,334,0}; // 每月的天数
int dir[8][2]= {{0,1},{0,-1},{-1,0},{1,0},{1,1},{1,-1},{-1,1},{-1,-1}}; // 八个方向的偏移量
bool isrun(int year)    // 判断是否为闰年的函数
{
    if((year%4==0&&year%100!=0)||(year%400==0))
        return true;    // 是闰年返回true
    return false;       // 不是闰年返回false
}
void getpri()           // 筛选素数的函数
{
    ll i;
    int j;
    cnt=0;
    memset(isprime,false,sizeof(isprime)); // 初始化isprime数组为false
    for(i=2; i<1000000LL; i++)  // 从2开始遍历到1000000
    {
        if(!isprime[i])prime[cnt++]=i;  // 若当前数是素数,则将其加入prime数组,并计数加一
        for(j=0; j<cnt&&prime[j]*i<1000000LL; j++)  // 将当前的素数与后面的数相乘,标记它们为非素数
        {
            isprime[i*prime[j]]=1;   // 将合数标记为true
            if(i%prime[j]==0)break;  // 若当前数能整除已有的素数,则跳出循环
        }
    }
}
ll qk_mul(ll a,ll b,ll mo)   // 快速乘运算,避免大数相乘溢出
{
    ll t=0;
    while(b)
    {
        if(b&1)
            t=(t+a)%mo;
        a=(a<<1)%mo;
        b>>=1;
    }
    t%=mo;
    return t;
}
ll qk_mod(ll a,ll b,ll mo)   // 快速模运算,避免大数取模溢出
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=qk_mul(ans,a,mo);
        a=qk_mul(a,a,mo);
        b>>=1;
    }
    ans%=mo;
    return ans;
}
int gcd(int a,int b)    // 求两个数的最大公约数
{
    return b == 0 ? a : gcd(b, a%b);
}
int bfs(int x)          // 广度优先搜索,用于找出某个节点到其他节点的最短路径
{
    int minx=x,mindis=0;// 最小节点和最短距离
    queue<ac> qu;
    qu.push(ac(x,0));    // 将起点加入队列
    vis[x]=1;            // 标记起点已访问
    while(!qu.empty())   // 队列非空时循环
    {
        ac u=qu.front();  // 取出队头节点
        int z=u.first;
        int y=u.second;
        qu.pop();         // 弹出队头节点
        if(mindis==y)     // 若当前距离和最短距离相等
        {
            minx=min(z,minx);  // 更新最小节点为较小的值
        }
        if(mindis<y)      // 若当前距离大于最短距离
        {
            mindis=y;     // 更新最短距离
            minx=z;       // 更新最小节点
        }
        for(int i=0;i<g[z].size();i++)  // 遍历当前节点的邻接节点
        {
            int v=g[z][i];
            if(!vis[v])   // 若邻接节点未被访问过
            {
                vis[v]=1;   // 标记为已访问
                qu.push(ac(v,y+1));  // 将邻接节点加入队列,并距离加一
            }
        }
    }
    if(mindis==0)
        return 0;   // 若最短距离为0,说明没有其他可达节点,返回0
    return minx;    // 返回最小节点
}
int main()
{
    int i,j,t,k;
    int u,v;
    scanf("%d%d%d",&n,&m,&k);  // 读入节点数、边数和查询次数
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);   // 读入每条边的起点和终点
        g[u].push_back(v);     // 将边加入图的邻接表中
        g[v].push_back(u);     // 无向图,所以需要加入反向边
    }
    int ans;
    for(i=0;i<k;i++)          // 进行k次查询
    {
        memset(vis,0,sizeof(vis));  // 初始化访问标记数组为0
        scanf("%d",&u);             // 读入查询的起点
        ans= bfs(u);                // 调用bfs函数找出最短路径
        printf("%d\n",ans);         // 输出结果
    }
    return 0;
}
重邮计算机考研改考408:四专业选择策略与备考指南 计算机专业基础综合(408)作为计算机考研的核心科目,涵盖数据结构、计算机组成原理、操作系统和计算机网络四大基础课程。其命题原理强调知识体系的完整性和综合应用能力,通过全国统一命题确保考试公平性。这一考试模式的技术价值在于能够系统检验考生的计算机科学基础,为研究生阶段的学术研究和工程实践奠定坚实基础。在考研备考场景中,408的复习需要科学的时间分配和策略调整,尤其对于重邮计算机学院新改考408的计算机科学与技术、软件工程等专业,考生需结合自身背景制定个性化备考方案。数据结构中的算法设计和计算机组成原理的数据 阅读详情

相关推荐

重庆邮电大学计算机考研408备考指南:四科均衡复习与专业选择

计算机考研408科目涵盖数据结构、计算机组成原理、操作系统和计算机网络四大核心课程,是衡量计算机专业基础能力的重要标准。其命题原理强调知识体系的完整性和交叉应用能力,要求考生不仅掌握单科知识点,还要理解各科目间的内在联系。从技术价值看,408考试能够系统检验学生对计算机系统底层原理、算法设计与网络通信等关键技术的掌握程度,为后续科研或工程实践打下坚实基础。在应用场景上,扎实的408知识体系尤其适合从事系统软件开发、人工智能算法优化、大数据平台构建等方向。以重庆邮电大学为例,其计算机科学与技术、软件工程等专业

weixin_34054866的博客 509

DS_SequenceLIst

其中List/* 保存线性表中最后一个元素的位置 */};L是用户传入的一个线性表,其中元素可以通过>、==、

m0_61758697的博客 1273

重邮计算机学院408考研指南:四专业对比与备考策略

计算机考研408统考是涵盖数据结构、计算机组成原理、操作系统和计算机网络四门核心课程的国家统一命题考试。其命题原理强调基础知识的系统性和综合运用能力,旨在全面评估考生的计算机专业素养。从技术价值看,408考试不仅提升考生的理论深度,还强化工程实践能力,为后续研究生学习和职业发展奠定坚实基础。在应用场景上,408成绩被众多高校计算机相关专业作为研究生入学的重要参考,尤其适用于重庆邮电大学计算机学院的计算机科学与技术、软件工程、人工智能和网络空间安全四个硕士专业。本文聚焦重邮计算机学院408考情,解析各专业特色

weixin_33716154的博客 367

(PTA)数据结构(作业)2、顺序表

作业,仅供参考,大佬轻喷,如有意见,那就是你对,谢谢

Misasagi Inori的博客 1万+

数据结构基础 浙江大学 作业答案

数据结构基础 浙江大学 作业答案 pdf

从SPICE到电磁场:非线性器件在CST场路协同仿真中的建模艺术

本文深入探讨了非线性器件在CST场路协同仿真中的建模技术,重点分析了SPICE模型与电磁场仿真的集成方法。通过对比线电流模型和面电流模型的优缺点,结合实际案例展示了二极管阵列在电磁散射调控中的应用,为工程师提供了优化仿真精度与效率的实用技巧。

pandas7gardener的博客 199

计算机专业数据结构试题答案

计算机专业数据结构试题答案

qq_42824842的博客 5172

51单片机STC8G1K08驱动ws2812记录

使用51单片机控制17个2812灯,这里选择STC8芯片,最大频率可以达到35M,参考网上的各种文章案例,使用定时器做的时候实测做不到规格书要求的245-345ns,STC8G1K08不带PWM,所以只能使用nop来做,好在单片机在这里只有做编程灯的功能,省略测试过程,下面是程序,使用的是24MHz内部晶振 //设置一个灯珠 void SendOnePix(unsigned char *ptr) { unsigned char i,j; unsigned char temp; fo...

的博客 7320

线性结构习题及解析

2-1 数组A[1…5,1…6]每个元素占5个单元,将其按行优先次序存储在起始地址为1000的连续的内存单元中,则元素A[5,5]的地址为: 1120 1125 1140 1145 解析: 2-2 对于顺序存储的长度为N的线性表,访问结点和增加结点的时间复杂度为: ...

Saniana的博客 8698

PICO4 VR开发调试神器:用Live Preview Plugin实现电脑串流,告别反复打包烧录的繁琐流程

本文详细介绍了PICO4 VR开发中如何使用Live Preview Plugin实现电脑串流,显著提升开发效率。通过实时预览和调试功能,开发者可以避免反复打包烧录的繁琐流程,特别适用于Unity环境下的VR应用开发。文章涵盖环境配置、连接设置、实时调试技巧及性能优化方案,是PICO4开发者的必备指南。

weixin_34110970的博客 418

实战测评:4大搜索API(You.com/Tavily/Exa/Perplexity)谁更适合你的AI项目?附Python调用代码

本文实战测评了You.com、Tavily、Exa和Perplexity四大搜索API在AI项目中的集成应用,详细对比了它们的技术特性和Python调用方法。针对LLM实时数据需求,You.com的优化设计表现突出,支持32k大上下文窗口和快速响应。文章提供了完整的代码示例和场景化选型建议,帮助开发者高效集成搜索API到AI项目中。

weixin_42569329的博客 479

【数据结构入门精讲 | 第二篇】考研408、企业面试基础概念习题

1.时间复杂度是根据算法写成的程序在执行时耗费时间的长度,往往与输入数据的规模有关。(对)2.斐波那契数列FN的定义为:F0=0, F1=1, F(N)=F(N−1)+F(N−2), N=2, 3, …用递归函数计算FN的空间复杂度是O(N)。(对)3.斐波那契数列FN的定义为:F0=0, F1=1, FN=FN−1+FN−2, N=2, 3, …。用循环函数计算FN的时间复杂度是Θ(FN).(错) 解析:在循环函数中,我们通过迭代的方式依次计算每个斐波那契数列

等风来 4273

超详细MySQL 8.0安装与配置

MySQL的安装与配置 还不会安装MySQL的同学们,还不会配置MySQL的同学们,赶紧按照下面步骤操作起来,超详细安装步骤如下: 进入MySQL官网 1、点击download 2、点击MySQL Community Server 3、选好选项点击go to download page 4、点击download 5、点击no thanks,just start my download 6、选Server only,点击Next 7、点击Execute 8、点击

Turniper的博客 8756

【数据结构入门精讲 | 第十八篇】考研408、企业面试图专项练习(一)

在上一篇中我们学习了图的相关知识点,在这一篇中我们进行图的专项练习。选择两城市间最经济的航行路线用迪杰斯特拉算法(对)2从某顶点出发进行深度优先遍历,最先退出dfs过程的是拓扑序列的最后一个顶点。(对)3对任意一个图,从某顶点出发进行一次深度优先或广度优先遍历,可访问图的所有顶点。(错)若存在回路,则结束遍历,剩下的节点就不能被访问。4检查有向图是否存在回路的一种方法是使用无前驱顶点优先算法对有向图进行拓扑排序。( 对 )5邻接矩阵如下:

等风来 4145

Go语言Gin框架项目:从零到一搭建一个用户管理系统

本文介绍了一个基于Go语言Gin框架开发的用户管理系统。系统采用MySQL数据库存储数据,使用Bootstrap 5构建现代化UI界面,实现了完整的CRUD功能。主要特点包括:RESTful API设计、前后端双重表单验证、实时搜索功能、SQL防注入措施以及响应式布局。项目结构清晰,包含数据库配置、用户模型、处理器和前端模板等模块。系统提供用户列表展示、新增/编辑表单、删除确认等功能,通过参数化查询确保安全性,并支持按姓名或邮箱搜索用户。

数据知道的博客 3995

从底层结构开始学习FPGA(8)----Block RAM(BRAM,块RAM)

BRAM作为FPGA底层的存储资源,作用很大,比如可以RAM/ROM/FIFO。

孤独的单刀 2万+

【数据结构入门精讲 | 第十六篇】并查集知识点及考研408、企业面试练习

在许多实际应用场景中,我们需要对元素进行分组,并且在这些分组中进行查询和修改操作。比如,在图论中,我们需要将节点按照连通性进行分组,以便进行最小生成树、最短路径等算法;在计算机视觉中,我们需要将像素进行分组,以便进行图像分割和对象识别等任务。而并查集正是为了解决这些问题而被提出来的一种数据结构。

等风来 4691

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

【数据结构入门精讲 | 第五篇】栈知识点及考研408、企业面试练习

栈是限定仅在栈顶(即表首)进行插入和删除操作的线性表,也称为后进先出(Last In First Out) 的线性表,简称 LIFO 结构。 栈的内部实现原理其实就是数组或链表的操作,而之所以引入 栈 这个概念,是为了将程序设计问题模型化,利用栈的先进后出特性对特定的一些问题进行简化。(栈是线性表的特例) 允许插入和删除元素的一端称为栈顶,另一端称为栈底,不含任何任何数据元素的栈称为空栈。

等风来 4599

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

【数据结构入门精讲 | 第十九篇】考研408、企业面试图专项练习(二)

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。 输入格式: 输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。 第二行给出N个正

等风来 3865

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

【数据结构入门精讲 | 第六篇】队列知识点及考研408、企业面试练习

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。 队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。

等风来 4625

【数据结构入门精讲 | 第十四篇】散列表知识点及考研408、企业面试练习(1)

散列表(Hash Table),也被称为哈希表或散列映射,是一种常用的数据结构之一。它通过将键(key)映射到值(value)来实现高效的数据存储和检索。散列表的主要思想是利用哈希函数将键转换成对应的索引,然后将值存储在该索引位置上。当需要查找或插入元素时,再次使用哈希函数计算出对应的索引,从而快速定位到目标位置。散列表的优势在于具有高效的查找和插入操作。由于直接通过索引进行访问,时间复杂度通常为O(1),即常数时间装填

等风来 4042

【数据结构入门精讲 | 第十五篇】散列表知识点及考研408、企业面试练习(2)

实现QQ新帐户申请和老帐户登陆的简化版功能。最大挑战是:据说现在的QQ号码已经有10位数了。输入格式:输入首先给出一个正整数N(≤105),随后给出N行指令。每行指令的格式为:“命令符(空格)QQ号码(空格)密码”。其中命令符为“N”(代表New)时表示要新申请一个QQ号,后面是新帐户的号码和密码;命令符为“L”(代表Login)时表示是老帐户登陆,后面是登陆信息。QQ号码为一个不超过10位、但大于1000(据说QQ老总的号码是1001)的整数。密码为不小于6位、不超过16位、且不包含空格的字符串。

等风来 4139

从LeetCode到考研408:时间/空间复杂度分析,如何成为你编程面试和笔试的“隐形加分项”?

本文深入探讨了时间复杂度和空间复杂度分析在编程面试和考研408中的关键作用,提供了从LeetCode到考研真题的实战指南。通过五步法分析框架、递归算法和嵌套循环的深度剖析,帮助读者掌握复杂度分析的技巧,提升在技术面试和笔试中的竞争力。

weixin_30680385的博客 387

2020考研经验分享——致学弟学妹

转眼间,20届考研已经落下帷幕,但21届考研才刚刚开始。今年我的考研成绩还不错 ,分享一下: 科目 分数 政治 72 英语二 73 数学二 117 专业综合 135 总分 397 政治和英语都还在预期之内,数学和专业课其实有些意料之外,尤其是专业课。 数学二今年题确实难,我的大题部分有好几个都没做出来,但是都把能写的写上了,好在我的小题(选择与填空)只错了1题...

AngelLover2017的博客 7916

计算机考研难度特别大吗,计算机考研难度大吗?学姐为你深度剖析

计算机考研,热门地区的热门学校,如今竞争比较激烈。但是非热门地区非热门院校,或者说非211其实还是简单的。互联网行业的快速发展和高薪水,让计算机成为当下最热门的考研专业,另一方面,传统行业的不景气让众多毕业生选择跨考计算机,期待能够逃离天坑。种种原因,让计算机考研竞争愈加激烈。同学们,你们知道计算机考研难度大吗?如果不知道,就来一起看看吧。一、计算机考研难度1.专业课难由《数据结构》《计算机网络》...

weixin_32384503的博客 6308
上一篇: 【数据结构入门精讲 | 第十三篇】考研408、公司面试树专项练习(二)
下一篇: 【数据结构入门精讲 | 第二篇】考研408、企业面试基础概念习题
秋说
秋说 优质创作者: 编程框架、信息安全技术领域 优质创作者: 编程框架、信息安全技术领域
博客等级 码龄4年 3万+粉丝 1906原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋说

感谢打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值