判断题
1-1.在具有N个结点的单链表中,访问结点和增加结点的时间复杂度分别对应为O(1)和O(N)。
F,访问节点的时间复杂度为O(N)
1-2.若用链表来表示一个线性表,则表中元素的地址一定是连续的。
F
1-3.将长度分别为m,n的两个单链表合并为一个单链表的时间复杂度为O(m+n)。
F,时间复杂度为O(1),如果是两个有序链表合成一个有序链表的时间复杂度为O(M + N)
1-4.单链表不是一种随机存取的存储结构。
T
选择题
2-1.设h为不带头结点的单向链表。在h的头上插入一个新结点t的语句是:
A.h=t; t->next=h->next;
B.t->next=h->next; h=t;
C.h=t; t->next=h;
D.t->next=h; h=t;
D
2-2.在单链表中,若p所指的结点不是最后结点,在p之后插入s所指结点,则执行
A.s->next=p; p->next=s;
B.s->next=p->next; p=s;
C.s->next=p->next; p->next=s;
D.p->next=s; s->next=p;
C
2-3.带头结点的单链表h为空的判定条件是: (2分)
A.h == NULL;
B.h->next == NULL;
C.h->next == h;
D.h != NULL;
B
2-4.将两个结点数都为N且都从小到大有序的单向链表合并成一个从小到大有序的单向链表,那么可能的最少比较次数是: (2分)
A.1
B.N
C.2N
D.NlogN
B
2-5.线性表若采用链式存储结构时,要求内存中可用存储单元的地址 (1分)
A.必须是连续的
B.连续或不连续都可以
C.部分地址必须是连续的
D.一定是不连续的
B
2-6.在具有N个结点的单链表中,实现下列哪个操作,其算法的时间复杂度是O(N)? (2分)
A.在地址为p的结点之后插入一个结点
B.删除开始结点
C.遍历链表和求链表的第i个结点
D.删除地址为p的结点的后继结点
C
2-7.对于一个具有N个结点的单链表,在给定值为x的结点后插入一个新结点的时间复杂度为 (2分)
A.O(1)
B.O(N/2)
C.O(N)
D.O(N2 )
C
2-8.链表不具有的特点是: (1分)
A.插入、删除不需要移动元素
B.方便随机访问任一元素
C.不必事先估计存储空间
D.所需空间与线性长度成正比
B
2-9.(neuDS)在一个含有n个结点的有序单链表中插入一个新结点,使单链表仍然保持有序的算法的时间复杂度是( )。
A.O(1)
B.O(log2n)
C.O(n)
D.O(n2 )
C
2-10.将长度为n的单链表连接在长度为m的单链表之后的算法的时间复杂度为( )。 (2分)
A.O(1)
B.O(m)
C.O(n)
D.O(n+m)
B
2-11.(neuDS)在单链表中,增加一个头结点的最终目的是为了
A.使单链表至少有一个结点
B.方便运算的实现
C.标识表结点中首结点的位置
D.说明单链表是线性表的链式存储
B
2-12.在单链表中,要删除某一指定结点,必须先找到该结点的()。 (2分)
A.直接前驱
B.自身位置
C.直接后继
D.直接后继的后继
A
2-13.以下关于链式存储结构的叙述中,()是不正确的。
A.结点除自身信息外还包括指针域,因此存储密度小于顺序存储结构
B.逻辑上相邻的结点物理上不必邻接
C.可以通过计算直接确定第i个结点的存储地址
D.插入、删除运算操作方便,不必移动结点
C
2-14.线性链表不具有的特点是()
A.随机访问
B.不必事先估计所需存储空间大小
C.插入与删除时不必移动元素
D.所需空间与线性长度成正比
A
2-15.线性表若采用链式存储结构时,要求内存中可用存储单元的地址()
A.必须是连续的
B.部分地址必须是连续的
C.一定是不连续的
D.连续或不连续都可以
D
2-16.对线性表,在下列情况下应当采用链表表示的是()。
A.经常需要随机地存取元素
B.经常需要进行插入和删除操作
C.表中元素需要占据一片连续的存储空间
D.表中的元素个数不变
B
2-17.不带表头附加结点的单链表为空的判断条件是头指针head满足条件
A.head==NULL
B.head->next==NULL
C.head->next== head
D.head!=NULL
A
2-18.可以用带表头附加结点的链表表示线性表,也可以用不带头结点的链表表示线性表,前者最主要的好处是()。)
A.可以加快对表的遍历
B.使空表和非空表的处理统一
C.节省存储空间
D.可以提高存取表元素的速度
B
函数题
6-1 带头结点的单链表就地逆置
本题要求编写函数实现带头结点的单链线性表的就地逆置操作函数。L是一个带头结点的单链表,函数ListReverse_L(LinkList &L)要求在不新开辟节点的前提下将单链表中的元素进行逆置,如原单链表元素依次为1,2,3,4,则逆置后为4,3,2,1。
函数接口定义:
void ListReverse_L(LinkList &L);
其中 L
是一个带头结点的单链表。
裁判测试程序样例:
//库函数头文件包含
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int ElemType; //假设线性表中的元素均为整型
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
Status ListCreate_L(LinkList &L,int n)
{
LNode *rearPtr,*curPtr; //一个尾指针,一个指向新节点的指针
L=(LNode*)malloc(sizeof (LNode));
if(!L)exit(OVERFLOW);
L->next=NULL; //先建立一个带头结点的单链表
rearPtr=L; //初始时头结点为尾节点,rearPtr指向尾巴节点
for (int i=1;i<=n;i++){ //每次循环都开辟一个新节点,并把新节点拼到尾节点后
curPtr=(LNode*)malloc(sizeof(LNode));//生成新结点
if(!curPtr)exit(OVERFLOW);
scanf("%d",&curPtr->data);//输入元素值
curPtr->next=NULL; //最后一个节点的next赋空
rearPtr->next=curPtr;
rearPtr=curPtr;
}
return OK;
}
void ListReverse_L(LinkList &L);
void ListPrint_L(LinkList &L){
//输出单链表
LNode *p=L->next; //p指向第一个元素结点
while(p!=NULL)
{
if(p->next!=NULL)
printf("%d ",p->data);
else
printf("%d",p->data);
p=p->next;
}
}
int main()
{
LinkList L;
int n;
scanf("%d",&n);
if(ListCreate_L(L,n)!= OK) {
printf("表创建失败!!!\n");
return -1;
}
ListReverse_L(L);
ListPrint_L(L);
return 0;
}
/* 请在这里填写答案 */
输入格式:
第一行输入一个整数n,表示单链表中元素个数,接下来一行共n个整数,中间用空格隔开。
输出格式:
输出逆置后顺序表的各个元素,两个元素之间用空格隔开,最后一个元素后面没有空格。
输入样例
4
1 2 3 4
输出样例
4 3 2 1
参考代码
void ListReverse_L(LinkList &L)
{
LNode *p, *q;
p = q = L -> next;
L -> next = NULL;
while(p != NULL)
{
q = q -> next;
p -> next = L -> next;
L -> next = p;
p = q;
}
}
不懂的话这个博客里面有张讲解图:戳一戳
6-2 单链表基本操作
实现单链表的初始化,插入、删除、访问等基本操作。 单链表为带头结点的单链表结构。
函数接口定义:
vtypedef char ElemType;
typedef struct LNode //定义单链表结点类型
{
ElemType data;
struct LNode *next;
} LinkList;
void InitList(LinkList *&L); //初始化一个为空的单链表。
void DestroyList(LinkList *&L); //销毁单链表。
void DispList(LinkList *L); //顺序输出链表每个结点,每个结点元素值以空格符间隔,以换行符结束。
bool ListInsert(LinkList *&L,int i,ElemType e); //在链表第i个结点位置处,插入元素值为e的结点,若插入成功,返回true,否则返回false.
bool ListDelete(LinkList *&L,int i,ElemType &e); //删除链表第i个结点,返回删除结点的元素值e,若删除成功,返回true,否则返回false
裁判测试程序样例:
#include <stdio.h>
#include <malloc.h>
typedef char ElemType;
typedef struct LNode //定义单链表结点类型
{
ElemType data;
struct LNode *next;
} LinkList;
void InitList(LinkList *&L);
void DestroyList(LinkList *&L);
void DispList(LinkList *L);
bool ListInsert(LinkList *&L,int i,ElemType e);
bool ListDelete(LinkList *&L,int i,ElemType &e);
int main()
{
LinkList *h;
ElemType e,ch;
InitList(h);
int i=1;
while((ch=getchar())!='\n')
{
ListInsert(h,i,ch);
i++;
}
DispList(h);
scanf("\n%d",&i);
if(ListDelete(h,i,e))
printf("delete %dth: %c\n",i,e);
else
printf("delete failed!\n");
DispList(h);
DestroyList(h);
return 0;
}
/* 请在这里填写答案 */
输入样例
在这里给出一组输入。例如:
abcdef
5
输出样例
在这里给出相应的输出。例如:
a b c d e f
delete 5th: e
a b c d f
参考代码
void InitList(LinkList *&L)
{
L = new LNode;
L -> next = NULL;
}
void DestroyList(LinkList *&L)
{
LinkList *q, *p = L;
while(p != NULL)
{
q = p -> next;
delete p;
p = q;
}
L = NULL;
}
void DispList(LinkList *L)
{
LinkList *p;
for(p = L -> next; p != NULL; p = p -> next)
printf("%c ",p -> data);
printf("\n");
}
bool ListInsert(LinkList *&L,int i,ElemType e)
{
LinkList *p = L;
int j = 0;
while(p && (j < i - 1))
{
p = p -> next;
++j;
}
if(!p || j > i - 1)
{
return false;
}
LinkList *s;
s = new LNode;
s -> data = e;
s -> next = p -> next;
p -> next = s;
return true;
}
bool ListDelete(LinkList *&L,int i,ElemType &e)
{
LinkList *q, *p = L;
int j = 0;
while((p -> next) && (j < i - 1))
{
p = p -> next;
++j;
}
if(!(p -> next) || (j > i - 1))
{
return false;
}
q = p -> next;
p -> next = q ->next;
e = q -> data;
delete q;
return true;
}
编程题
7-1 两个有序链表序列的合并
已知两个非降序链表序列S1与S2,设计函数构造出S1与S2合并后的新的非降序链表S3。
输入格式:
输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。
输出格式:
在一行中输出合并后新的非降序链表,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL
。
输入样例
1 3 5 -1
2 4 6 8 10 -1
输出样例
1 2 3 4 5 6 8 10
参考代码
#include<bits/stdc++.h>
using namespace std;
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
} LNode,*LinkList;
void Create(LinkList &L)
{
LNode *p = L;
int n;
while((p->next) != NULL)
{
p = p->next;
}
cin>>n;
while(n != -1)
{
LNode *tmp = (LNode*)malloc(sizeof(LNode));
tmp -> data = n;
p -> next = tmp;
tmp -> next = NULL;
cin>>n;
p = p -> next;
}
}
void Combine(LinkList &s1,LinkList &s2,LinkList &s3)
{
LNode *l1, *l2, *l3;
l1 = s1 -> next;
l2 = s2 -> next;
l3 = s3;
while(l1 && l2)
{
if(l1 -> data <= l2 -> data)
{
l3 -> next = l1;
l1 = l1 -> next;
}
else
{
l3 -> next = l2;
l2 = l2 -> next;
}
l3 = l3 -> next;
}
l3 -> next = l1 ? l1 : l2;
s1 -> next = NULL;
s2 -> next = NULL;
}
void Print(LinkList &L)
{
LNode *p = L -> next;
if(p == NULL)
cout<<"NULL";
while(p != NULL)
{
if(p -> next != NULL)
cout<<p -> data<<" ";
else
cout<<p -> data;
p = p->next;
}
}
int main()
{
LinkList S1, S2, S3;
S1 = (LinkList)malloc(sizeof(LNode));
S1 -> next = NULL;
S2 =(LinkList)malloc(sizeof(LNode));
S2 -> next = NULL;
S3 = (LinkList)malloc(sizeof(LNode));
S3 -> next = NULL;
Create(S1);
Create(S2);
Combine(S1, S2, S3);
Print(S3);
return 0;
}
7-2 两个有序链表序列的交集
已知两个非降序链表序列S1与S2,设计函数构造出S1与S2的交集新链表S3。
输入格式:
输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。
输出格式:
在一行中输出两个输入序列的交集序列,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL
。
输入样例
1 2 5 -1
2 4 5 8 10 -1
输出样例
2 5
参考代码
#include<bits/stdc++.h>
using namespace std;
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
} LNode,*LinkList;
void Create(LinkList &L)
{
LNode *p = L;
int n;
while((p->next) != NULL)
{
p = p->next;
}
cin>>n;
while(n != -1)
{
LNode *tmp = (LNode*)malloc(sizeof(LNode));
tmp -> data = n;
p -> next = tmp;
tmp -> next = NULL;
cin>>n;
p = p -> next;
}
}
void Union(LinkList s1,LinkList s2,LinkList &s3)
{
LNode *l1, *l2, *tmp, *cur = s3;
l1 = s1 -> next;
l2 = s2 -> next;
while(l1&&l2)
{
if(l1 -> data < l2 -> data)
{
l1 = l1 -> next;
}
else if(l1 -> data > l2 -> data)
{
l2 = l2 -> next;
}
else
{
tmp = (LNode*)malloc(sizeof(LNode));
tmp -> data = l1 -> data;
tmp -> next = NULL;
cur -> next = tmp;
cur = tmp;
l1 = l1 -> next;
l2 = l2 -> next;
}
}
}
void Print(LinkList &L)
{
LNode *p = L -> next;
if(p == NULL)
cout<<"NULL";
while(p != NULL)
{
if(p -> next != NULL)
cout<<p -> data<<" ";
else
cout<<p -> data;
p = p->next;
}
}
int main()
{
LinkList S1, S2, S3;
S1 = (LinkList)malloc(sizeof(LNode));
S1 -> next = NULL;
S2 =(LinkList)malloc(sizeof(LNode));
S2 -> next = NULL;
S3 = (LinkList)malloc(sizeof(LNode));
S3 -> next = NULL;
Create(S1);
Create(S2);
Union(S1, S2, S3);
Print(S3);
return 0;
}