在上一篇中我们介绍了表的相关概念,这篇文章我们进行表的专项练习。
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值。(错)
三对角矩阵除了第一行和最后一行是每行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
给定一个顺序存储的线性表,请设计一个函数删除所有值大于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
#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--;
}
}
}
本题要求实现一个对数组进行循环左移的简单函数:一个数组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
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]);
}
给定一个顺序存储的线性表,请设计一个算法查找该线性表中最长的连续递增子序列。例如,(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
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]);
}
给定一系列正整数,请设计一个尽可能高效的算法,查找倒数第K个位置上的数字。
输入格式:
输入首先给出一个正整数K,随后是若干非负整数,最后以一个负整数表示结尾(该负数不算在序列内,不要处理)。
输出格式:
输出倒数第K个位置上的数据。如果这个位置不存在,输出错误信息NULL
。
输入样例:
4 1 2 3 4 5 6 7 8 9 0 -1
输出样例:
7
#include
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
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指向的也应为空。
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; // 返回反转后的链表头节点指针
}
给定一个带头结点的单链表和一个整数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
#include
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;
}
}
}
喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂—喂喂喂……”的呼唤。呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的“讯号”,达到声讯传递交流的目的。原来它是彝族先民用来求援呼救的“讯号”,慢慢地人们在生活实践中发现了它的实用价值,便把它作为一种交流工具世代传袭使用。
一个山头呼喊的声音可以被临近的山头同时听到。题目假设每个山头最多有两个能听到它的临近山头。给定任意一个发出原始信号的山头,本题请你找出这个信号最远能传达到的地方。
输入格式:
输入第一行给出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
#include
#include
#include
#include
#include
#include
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;
}
以上就是本篇文章的全部内容,下一篇文章中我们将介绍栈的相关知识点。