PTA数据结构与算法-第二章——线性表
文章目录第一章——褚论第二章——线性表第三章——栈与队列第一章——褚论第二章——线性表第三章——栈与队列对于顺序存储的长度为N的线性表,访问结点和增加结点的时间复杂度分别对应为O(1)和O(N)。T 题目字眼 “ 顺序存储 ” ,说明内存单元中分配的存储空间是连续的,所 以该线性表为数组形式存储,所以数组访问时,通过下标可随机访问,时间复杂度为O(1),而增加插入时,需要涉及大量元素的移动,所以时
第一章——褚论
第二章——线性表
第三章——栈与队列
第四章——字符串
第五章——树与二叉树
第六章——图
第七章——排序
第八章——检索
判断题
- 对于顺序存储的长度为N的线性表,访问结点和增加结点的时间复杂度分别对应为O(1)和O(N)。
T 题目字眼 “ 顺序存储 ” ,说明内存单元中分配的存储空间是连续的,所 以该线性表为数组形式存储,所以数组访问时,通过下标可随机访问,时间复杂度为O(1),而增加插入时,需要涉及大量元素的移动,所以时间复杂度为O(N)。
- 线性表采用链式存储表示时,所有结点之间的存储单元地址可以连续也可以不连续。
T
- 将长度分别为m,n的两个单链表合并为一个单链表的时间复杂度为O(m+n)。
F 时间复杂度为O(1)
- 在具有头结点的链式存储结构中,头指针指向链表中的第一个元素结点。
F
头指针和头结点的区别:
头指针:
–头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针
–头指针具有标识作用,所以头指针冠以链表的名字(指针变量的名字)
--无论链表是否为空,头指针均不为空
–头指针是链表的必要元素
头结点:
–头结点是为了操作的统一和方便而设立的,放在第一个元素的结点之前,其数据域一般无意义(但也可以用来存放链表的长度)
–有了头结点,对在第一元素结点前插入结点和删除第一结点起操作与其它结点的操作就统一了
–头结点不一定是链表的必要元素
- 若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除运算,则利用顺序表存储最节省时间。
T
- 对于顺序存储的长度为N的线性表,删除第一个元素和插入最后一个元素的时间复杂度分别对应为O(1)和O(N)。
F 应该分别对应为O(N)和O(1)。
- 在具有N个结点的单链表中,访问结点和增加结点的时间复杂度分别对应为O(1)和O(N)。
F 访问为O(N),增加结点为O(1).
- 所谓随机存取,就是通过首地址和元素的位序号值可以在O(1)的时间内找到指定的元素。
T
- 顺序表上进行插入、删除操作时需要移动元素的个数与待插入或待删除元素的位置无关。
F 有关
- 在线性表的顺序存储结构中可实现快速的随机存取,而在链式存储结构中则只能进行顺序存取。
T
- 线性表的长度是指线性表所占用的存储空间的大小。
F 线性表所占用的存储空间大小为:每个结点所占用的存储字节数乘以线性表的长度。
- 循环链表不是线性表。
F
“线性表”中的“线性”是逻辑结构的概念,是指
(1)开始结点和终端结点都是唯一的;
(2)除了开始结点和终端结点,其余结点都有且仅有一个直接前驱,有且仅有一个直接后继。
“循环链表”中的“链表”是存储结构的概念, 是指
不要求逻辑上相邻的结点在物理上也相邻,结点间的逻辑关系是由附加的指针字段表示的。
综上 ,循环链表也是链表的一种,链表满足线性表的条件,所以循环链表自然也属于线性表。
- 下列函数试图求链式存储的线性表的表长,是否正确?
int Length ( List *PtrL )
{ List *p = PtrL;
int j = 0;
while ( p ) {
p++;
j++;
}
return j;
}
F 不能通过p++来访问下一个元素的,链式存储的话一般都是需要p=p->next;
单选题
- 带头结点的单链表h为空的判定条件是:
h == NULL;
h->next == NULL;
h->next == h;
h != NULL;
头结点是不含有数据元素的结点,它的下一个结点才是存放信息的。故判定为空的依据应该是h->next是否为空。
- 在双向链表存储结构中,删除p所指的结点,相应语句为:
p->prior=p->prior->prior; p->prior->next=p;
p->next->prior=p; p->next=p->next->next;
p->prior->next=p->next; p->next->prior=p->prior;
p->next=p->prior->prior; p->prior=p->next->next;
- 已知L是带头结点的单链表,则摘除首元结点的语句是( )。
L=L->link;
L->link=L->link->link;
L=L->link->link;
L->link = L;
- 阅读下列程序,该算法的功能是()。
typedef struct node{
ElemType data;
struct node *next;
}LNode;
void fun2(LNode *&h){
LNode *p, *q, *r;
if (h==NULL) return;
p=h;
q=h->next;
while (q!=h )
{
r=q->next;
q->next=p;
p=q;
q=r;
}
h->next=p;
h=p;
}
将单链表逆置
将单循环链表逆置
从头到尾遍历单链表
从头到尾遍历单循环链表
- 数组A[1…5,1…6]每个元素占5个单元,将其按行优先次序存储在起始地址为1000的连续的内存单元中,则元素A[5,5]的地址为:
1120
1125
1140
1145
1000+(6 * 5) * 4+5 * 5=1145
但是1145是A[5,5]之后的内存单元的地址(也就是A[5,6]的首地址)。因此A[5,5]的首地址是1145-5=1140.
- 在N个结点的顺序表中,算法的时间复杂度为O(1)的操作是:
访问第i个结点(1≤i≤N)和求第i个结点的直接前驱(2≤i≤N)
在第i个结点后插入一个新结点(1≤i≤N)
删除第i个结点(1≤i≤N)
将N个结点从小到大排序
- 若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除运算,则利用哪种存储方式最节省时间?
双链表
单循环链表
带头结点的双循环链表
顺序表
- 链表不具有的特点是:
插入、删除不需要移动元素
方便随机访问任一元素
不必事先估计存储空间
所需空间与线性长度成正比
- 已知表头元素为c的单链表在内存中的存储状态如下表所示:
现将f存放于1014H处,并插入到单链表中,若f在逻辑上位于a和e之间,则a、e、f的“链接地址”依次
是:
1010H, 1014H, 1004H
1010H, 1004H, 1014H
1014H, 1010H, 1004H
1014H, 1004H, 1010H
这里的链接地址即为链表中next指针,根据表中内容可知a->e->b->d,a和e中插入f,所以a的链接地址即为f的地址1014H,而e的链接地址不变为1004H,f的链接地址为e的地址即1010H。
- 数据结构反映了数据元素之间的结构关系。单链表是一种( )。
顺序存储线性表
非顺序存储非线性表
顺序存储非线性表
非顺序存储线性表
- 在具有N个结点的单链表中,实现下列哪个操作,其算法的时间复杂度是O(N)?
在地址为p的结点之后插入一个结点
删除开始结点
遍历链表和求链表的第i个结点
删除地址为p的结点的后继结点
其余三项操作时间复杂度均为O(1)。
- 某线性表中最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用什么存储方式最节省运算时间?
单链表
仅有尾指针的单循环链表
仅有头指针的单循环链表
双链表
- 将线性表La和Lb头尾连接,要求时间复杂度为O(1),且占用辅助空间尽量小。应该使用哪种结构?
单链表
单循环链表
带尾指针的单循环链表
带头结点的双循环链表
- 对于一个具有N个结点的单链表,在给定值为x的结点后插入一个新结点的时间复杂度为
O(1)
O(N/2)
O(N)
O(N2 )
- 与单链表相比,双链表的优点之一是()。
插入、删除操作更加简单
可随机访问
可以省略表头指针或表尾指针
顺序访问相邻结点更加灵活
- 将长度为n的单链表链接在长度为m的单链表之后的算法的时间复杂度为()。
O(1)
O(n)
O(m)
O(m+n)
需要从长度为m的单链表的头指针遍历完到最后一个元素的地方然后接入长度为n的单链表,故算法的时间复杂度应该为被链接的链表的长度即O(m)
- 以下说法错误的是 ( )
对于线性表来说,定位运算LocateElem在顺序表和单链表上的时间复杂度均为O(n)
插入、删除操作在顺序表上的实现,平均时间复杂度为O(n)
在链表上实现读表元运算的平均时间复杂度为O(1)
插入、删除操作在链表上的实现可在O(1)时间内完成
其中,定位运算LocateElem是指给定元素x在线性表中找到x并进行运算所以第一项正确。
- 链表 - 存储密度
链表的存储密度 ▁▁▁▁
大于 1
等于 1
小于 1
不能确定
程序填空题
- 本题目要求以头插法建立单链表。
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
LinkList Create();
void print( LinkList L);
int main()
{
LinkList L = Create();
print(L);
return 0;
}
LinkList Create()
{
LinkList L,s;
ElemType e;
L = (LinkList)malloc(sizeof(LNode));
L->next=NULL
;
scanf("%d",&e);
while(e!=-1)
{
s = (LinkList)malloc(sizeof(LNode));
s->data=e;
s->next = L->next
;
L->next=s
;
scanf("%d",&e);
}
return L
;
}
void print(LinkList L)
{
LinkList p;
p=L->next;
while (p)
{
printf("%d ", p->data);
p =p->next;
}
}
输入格式:
输入数据为若干正整数,最后以-1表示结尾(-1不算在序列内,不要处理)。所有数据之间用空格分隔。
输入样例:
1 2 3 4 5 6 7 8 9 -1
输出样例:
9 8 7 6 5 4 3 2 1
- 已知单链表LA和LB的元素按值非递减排列 归并LA和LB得到新的单链表LC,LC的元素也按值非递减排列
#include<iostream>
using namespace std;
#define ERROR 0
typedef struct LNode
{
int data;
struct LNode *next;
} LNode, *LinkList;
void InitList_L(LinkList &L)
{
L = new LNode;
L->next = NULL;
}
void input(LinkList &L, int n)
{
int i=0;
LNode *p, *r;
r = L;
while (i<n) {
p = new LNode;
cin >> p->data;
p->next = NULL;
r->next = p;
r = p;
i++;
}
}
void output(LinkList L)
{
int i = 0;
LNode *p;
p = L->next;
while (p) {
if (i)
cout << ",";
cout << p->data;
p = p->next;
i = 1;
}
}
void MergeList_L(LinkList &LA, LinkList &LB, LinkList &LC)
{
LinkList pa, pb, pc;
pa = LA->next;
pb = LB->next;
LC = LA;
pc = LC;
while(
pa && pb
)
{
if (pa->data <= pb->data)
{
pc->next = pa;
pc = pa;
pa = pa->next;
} else {
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
pc->next = pa ? pa : pb;
delete LB;
}
int main() {
LinkList La, Lb, Lc;
int num_a, num_b;
cin >> num_a >> num_b;
InitList_L(La);
input(La, num_a);
InitList_L(Lb);
input(Lb, num_b);
InitList_L(Lc);
MergeList_L(La, Lb, Lc);
output(Lc);
return 0;
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)