1、在具有N个结点的单链表中,访问结点和增加结点的时间复杂度分别对应为O(1)和O(N)。F
.单链表访问前驱结点的时间复杂度为O(N),访问后继结点的时间复杂度为O(1)。
.增加结点也分为前插和后插两种情况:前插的时间复杂度为O(N),后插的时间复杂度为O(1)。
原因如下 :访问(增加)前驱结点需要从头开始顺序访问,而访问(增加)后继结点只需要进行一次间接寻址的操作。
2、将N个数据按照从小到大顺序组织存放在一个单向链表中。如果采用二分查找,那么查找的平均时间复杂度是O(logN)。F
二分查找的平均复杂度是O(logN),用在数组上。而链表是不能用二分查找的,链表只能顺序访问,顺序查找。
3、若用链表来表示一个线性表,则表中元素的地址一定是连续的。F
链表中的地址可能连续可能不连续,结点内的地址是连续的。
4、单链表不是一种随机存取的存储结构。T
5、取线性表的第i个元素的时间同i的大小有关。F
线性表分为顺序表和链表。
顺序表访问第i个结点的时间复杂度是O(1),与顺序表的长度无关,它是通过下标(索引)直接访问的。
而链表是通过指针访问结点,需要通过指针一个一个顺序访问,链表取第i个元素的时间同i的大小有关。
6、线性表采用链式存储表示时,所有结点之间的存储单元地址可以连续也可以不连续。T
7、顺序存储方式插入和删除时效率太低,因此它不如链式存储方式好。F
两者各有优缺点,虽然顺序存储插入和删除效率确实低,但是它访问目标结点比链式存储快。
而且删除的时候后边不前移的话,比链式存储还快,不是吗?doge
8、线性表的顺序存储表示优于链式存储表示。F
顺序存储需要开辟一个定长的空间,读写速度快,缺点是不可扩充容量(如果要扩充需要开辟一个新的足够大的空间把原来的数据重写进去)
链式存储无需担心容量问题,读写速度相对慢些,由于要存储下一个数据的地址所以需要的存储空间比顺序存储大。
9、在单链表中,要访问某个结点,只要知道该结点的指针即可。因此,单链表是一种随机存取结构。F
顺序表才是随机存取结构,链表是顺序存取结构,链表里即使知道了该结点的指针,如果要访问其他结点还是需要从已知的结点的指针开始顺序访问,除非直接知道所有结点的指针,n个结点n个已知地址的指针,不现实。
10、在具有头结点的链式存储结构中,头指针指向链表中的第一个元素结点。F
头指针和头结点的区别:
头指针:
–头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针
–头指针具有标识作用,所以头指针冠以链表的名字(指针变量的名字)
--无论链表是否为空,头指针均不为空
–头指针是链表的必要元素
头结点:
–头结点是为了操作的统一和方便而设立的,放在第一个元素的结点之前,其数据域一般无意义(但也可以用来存放链表的长度)
–有了头结点,对在第一元素结点前插入结点和删除第一结点起操作与其它结点的操作就统一了
–头结点不一定是链表的必要元素
11、在一个设有头指针和尾指针的单链表中,执行删除该单链表中最后一个元素的操作与链表的长度无关。F
删除最后一个元素需要知道其前驱结点,使前驱结点的指针指向NULL,而仅有头尾指针的单链表想要访问到最后一个元素的前驱结点依旧需要从头到尾顺序访问,所以有关。
12循环链表不是线性表。F
链表和顺序表都是线性表,跟循环不循环无关,线性表的定义是数据元素之间一对一。
13、带头结点的单循环链表中,任一结点的后继结点的指针域均不空。T
选择题
1、线性表若采用链式存储结构时,要求内存中可用存储单元的地址
A.必须是连续的
B.连续或不连续都可以
C.部分地址必须是连续的
D.一定是不连续的
线性表链式存储结构的特点是:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的。)
2、某线性表中最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用什么存储方式最节省运算时间?
A.单链表
B.仅有尾指针的单循环链表
C.仅有头指针的单循环链表
D.双链表
单链表,仅有头指针的循环链表,双链表都需要从头遍历到尾才能在最后一个元素之后插入,此时是O(1).
单循环链表中有尾指针即可立刻得到最后一个元素和第一个元素的地址。
3、若某表最常用的操作是在最后一个结点之后插入一个结点或删除最后一个结点。则采用哪种存储方式最节省运算时间?
A.单链表
B.双链表
C.单循环链表
D.带头结点的双循环链表
ABC想要在最后一个结点之后插入的话,需要从头遍历到尾才能插入,此时是O(N).
而D可以通过指向上一个结点的指针立刻得到最后一个结点以及倒数第二个结点,然后进行插入和删除操作,此时是O(1).
4、将线性表La和Lb头尾连接,要求时间复杂度为O(1),且占用辅助空间尽量小。应该使用哪种结构?
A.单链表
B.单循环链表
C.带尾指针的单循环链表
D.带头结点的双循环链表
ABD都需要从头开始到尾,时间复杂度是O(N)
而带尾指针的单循环链表,尾指针的下一个即为头结点,连接的时间复杂度是O(1).
5、线性表L在什么情况下适用于使用链式结构实现?
A.需不断对L进行删除插入
B.需经常修改L中的结点值
C.L中含有大量的结点
D.L中结点结构复杂
链式结构插入和删除的算法是O(1),而顺序结构的插入和删除的算法是O(N)。
6、对于一个具有N个结点的单链表,在给定值为x的结点后插入一个新结点的时间复杂度为
A.O(1)
B.O(N/2)
C.O(N)
D.O()g
插入的算法为O(1),而首先要找到x的时间复杂度为O(N)。
7、链表不具有的特点是:
A.插入、删除不需要移动元素
B.方便随机访问任一元素
C.不必事先估计存储空间
D.所需空间与线性长度成正比
8、设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;
9、在单链表中,若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;
10、带头结点的单链表h
为空的判定条件是:
A.h == NULL;
B.h->next == NULL;
C.h->next == h;
D.h != NULL;
11、对于一非空的循环单链表,h
和p
分别指向链表的头、尾结点,则有:
A.p->next == h
B.p->next == NULL
C.p == NULL
D.p == h
12、在双向链表存储结构中,删除p
所指的结点,相应语句为:
A.p->prior=p->prior->prior; p->prior->next=p;
B.p->next->prior=p; p->next=p->next->next;
C.p->prior->next=p->next; p->next->prior=p->prior;
D.p->next=p->prior->prior; p->prior=p->next->next;
13、将两个结点数都为N且都从小到大有序的单向链表合并成一个从小到大有序的单向链表,那么可能的最少比较次数是:
A.1
B.N
C.2N
D.NlogN
14、
已知表头元素为c
的单链表在内存中的存储状态如下表所示:
现将f
存放于1014H
处,并插入到单链表中,若f
在逻辑上位于a
和e
之间,则a
、e
、f
的“链接地址”依次是:
A.1010H
, 1014H
, 1004H
B.1010H
, 1004H
, 1014H
C.1014H
, 1010H
, 1004H
D.1014H
, 1004H
, 1010H
15、在单链表中,指针p指向元素为x的结点,实现“删除x的后继”的语句是()。
A.p=p->next
B.p->next=p->next->next
C.p->next=p
D.p=p->next->next
16、非空的循环单链表head的尾结点(由p所指向)满足()。
A.p->next == NULL
B.p == NULL
C.p->next == head
D.p == head
函数题
7-1 两个有序链表序列的合并 (18 分)
已知两个非降序链表序列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 struct lnode
{
int data;
lnode *next;
} lnode;
int main()
{
lnode *head1 = (lnode*)malloc(sizeof(lnode)),*r1 = head1;
lnode *head2 = (lnode*)malloc(sizeof(lnode)),*r2 = head2;
lnode *head3 = (lnode*)malloc(sizeof(lnode)),*r3 = head3;
int num;
while(cin>>num && num!=-1)
{
lnode *p = (lnode*)malloc(sizeof(lnode));
p->data = num;
p->next = NULL;
r1->next = p;
r1 = p;
}
while(cin>>num && num!=-1)
{
lnode *p = (lnode*)malloc(sizeof(lnode));
p->data = num;
p->next = NULL;
r2->next = p;
r2 = p;
}
lnode *s;
head1 = head1->next;
head2 = head2->next;
while(head1 && head2)
{
if(head1->data < head2->data)
{
s = head1;
head1 = head1->next;
s->next = NULL;
r3->next = s;
r3 = r3->next;
}
else
{
s = head2;
head2 = head2->next;
s->next = NULL;
r3->next = s;
r3 = s;
}
}
if(!head1) head1 = head2;
while(head1)
{
s = head1;
head1 = head1->next;
s->next = NULL;
r3->next = s;
r3 = r3->next;
}
if(head3->next == NULL) {cout<<"NULL";return 0;}
int flag=1;
head3 = head3->next;
while(head3)
{
if(flag==1)
{
cout<<head3->data;
flag =0;
}
else cout<<' '<<head3->data;
head3 = head3->next;
}
}
/* 急着打游戏,不想写了就复制了,时隔多日写一遍简单测试了一下,不知道能不能过全部检测点
#include <iostream>
using namespace std;
struct listNode {
int date;
struct listNode* next;
};
struct listNode* creatList()
{
int num;
cin >> num;
struct listNode* head = (struct listNode*)malloc(sizeof(listNode));
struct listNode* s1 = head;
while (num != -1)
{
struct listNode* p = (struct listNode*)malloc(sizeof(listNode));
p->date = num;
p->next = NULL;
s1->next = p;
s1 = s1->next;
cin >> num;
}
return head;
}
void printList(struct listNode* q)
{
q = q->next;
if (q == NULL)
{
cout << "NULL";
return;
}
while (q)
{
if (q->next != NULL)
cout << q->date << " ";
if (q->next == NULL)
cout << q->date;
q = q->next;
}
}
struct listNode* mergeList(struct listNode* m, struct listNode* n)
{
struct listNode* head = (struct listNode*)malloc(sizeof(listNode));
struct listNode* r = head;
m = m->next;
n = n->next;
while (m && n)
{
struct listNode* s = (struct listNode*)malloc(sizeof(listNode));
s->next = NULL;
r->next = s;
if (m->date < n->date)
{
s->date = m->date;
m = m->next;
}
else if (m->date >= n->date)
{
s->date = n->date;
n = n->next;
}
r = r->next;
}
if (m)
{
r->next = m;
}
else if (n)
{
r->next = n;
}
return head;
}
int main()
{
struct listNode* S1 = creatList();
struct listNode* S2 = creatList();
struct listNode* S3 = mergeList(S1, S2);
printList(S3);
}
*/
7-2 两个有序链表序列的交集 (18 分)
已知两个非降序链表序列S1与S2,设计函数构造出S1与S2的交集新链表S3。
输入格式:
输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。
输出格式:
在一行中输出两个输入序列的交集序列,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL
。
输入样例:
1 2 5 -1
2 4 5 8 10 -1
输出样例:
2 5
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
struct Node *build();
struct Node *operate(struct Node *a,struct Node *b);
int main()
{
struct Node *a,*b,*c;
a=build();
b=build();
c=operate(a,b);
if(!c)
printf("NULL\n");
while(c)
{
if(c->next==NULL)
printf("%d",c->data);
else
printf("%d ",c->data);
c=c->next;
}
}
struct Node *build()
{
int a;
struct Node *head=NULL,*str=NULL;
scanf("%d",&a);
while(a!=-1)
{
struct Node *p=(struct Node*)malloc(sizeof(struct Node));
p->data=a;
p->next=NULL;
if(head==NULL)
head=p;
else
str->next=p;
str=p;
scanf("%d",&a);
}
return head;
}
struct Node *operate(struct Node *a,struct Node *b)
{
struct Node *head=NULL,*str=NULL;
while(a&&b)
{
if((a->data)<(b->data))
a=a->next;
else if((a->data)>(b->data))
b=b->next;
else if((a->data)==(b->data))
{
if(head==NULL)
head=a;
else
str->next=a;
str=a;
a=a->next;
b=b->next;
str->next=NULL;//放在这里很重要,要先将a进至下一节点,防止直接将链表a中断
}
}
return head;
}
/*同上的理由hhhhhh
#include <iostream>
using namespace std;
struct listNode {
int date;
struct listNode* next;
};
struct listNode* creatList()
{
int num;
cin >> num;
struct listNode* head = (struct listNode*)malloc(sizeof(listNode));
struct listNode* s1 = head;
while (num != -1)
{
struct listNode* p = (struct listNode*)malloc(sizeof(listNode));
p->date = num;
p->next = NULL;
s1->next = p;
s1 = s1->next;
cin >> num;
}
return head;
}
void printList(struct listNode* q)
{
q = q->next;
if (q == NULL)
{
cout << "NULL";
return;
}
while (q)
{
if (q->next != NULL)
cout << q->date << " ";
if (q->next == NULL)
cout << q->date;
q = q->next;
}
}
struct listNode* mergeList(struct listNode* m, struct listNode* n)
{
struct listNode* head = (struct listNode*)malloc(sizeof(listNode));
struct listNode* r = head;
m = m->next;
n = n->next;
while (m && n)
{
if (m->date == n->date)
{
struct listNode* s = (struct listNode*)malloc(sizeof(listNode));
s->next = NULL;
r->next = s;
s->date = m->date;
m = m->next;
n = n->next;
r = r->next;
}
else if(m->date < n->date)
{
m = m->next;
}
else if (m->date > n->date)
{
n = n->next;
}
}
return head;
}
int main()
{
struct listNode* S1 = creatList();
struct listNode* S2 = creatList();
struct listNode* S3 = mergeList(S1, S2);
printList(S3);
}
*/
7-3 求链式线性表的倒数第K项 (18 分)
给定一系列正整数,请设计一个尽可能高效的算法,查找倒数第K个位置上的数字。
输入格式:
输入首先给出一个正整数K,随后是若干非负整数,最后以一个负整数表示结尾(该负数不算在序列内,不要处理)。
输出格式:
输出倒数第K个位置上的数据。如果这个位置不存在,输出错误信息NULL
。
输入样例:
4 1 2 3 4 5 6 7 8 9 0 -1
输出样例:
7
#include<bits/stdc++.h>
using namespace std;
typedef struct LNode{
int x, n;
struct LNode *next;
}LNode, *LinkList;
void CreaterList(LinkList &newL){
//采用从链表头部插入新节点
int a, sum = 0;
LinkList p;
newL = new LNode;
newL->next = NULL;
while(scanf("%d", &a) == 1 && a >= 0){
sum++;
p = new LNode;
p->x = a;
p->next = newL->next;
newL->next = p;
}
newL->n = sum;
}
void Solve(LinkList &solveL, int k)
{
if(k > solveL->n) {
printf("NULL\n"); return ;}
LinkList p = solveL->next;
int sum = 0;
while(p){
sum++;
if(sum == k) {
printf("%d\n", p->x); break;}
p = p->next;
}
return ;
}
int main()
{
LinkList L1;
int K;
scanf("%d", &K);
CreaterList(L1); //建表
Solve(L1, K);
return 0;
}
/*同上的理由hhhhhhhhhhhhhhhhh
#include <iostream>
using namespace std;
struct listNode {
int listNodeLength;
int date;
struct listNode* next;
};
struct listNode* creatList()
{
int num,listLength;
cin >> num;
listLength = 0;
struct listNode* head = (struct listNode*)malloc(sizeof(listNode));
struct listNode* s1 = head;
while (num >= 0)
{
struct listNode* p = (struct listNode*)malloc(sizeof(listNode));
p->date = num;
p->next = NULL;
s1->next = p;
s1 = s1->next;
cin >> num;
listLength++;
}
head->listNodeLength = listLength;
return head;
}
void numberAddress(int number,struct listNode* m)
{
int n = 1;
int len = m->listNodeLength;
m = m->next;
while (m->date != number)
{
n++;
if (m->next == NULL)
{
break;
}
m = m->next;
}
n = len - n + 1 ;
if (n == 0)
{
cout << "NULL";
return;
}
cout << n;
}
int main()
{
int number;
cin >> number;
struct listNode* S1 = creatList();
numberAddress(number, S1);
}
*/
参考:
“数据结构——链表”作业答案分析(判断+选择)_CKinLay的博客-CSDN博客_链表是一种随机存取的存储结构
PTA数据结构与算法-第二章——线性表_?Suki的博客-CSDN博客
7-2 两个有序链表序列的交集(简单解法,推荐)_才疏学浅易大师的博客-CSDN博客_两个有序链表序列的交集
C++实现单链表(含完整代码)_拾贰VII的博客-CSDN博客_c++单链表的实现
仅供参考,欢迎交流,共同进步,喷就是你对。
函数第一个和第三个明明也是复制的,但是找不到了,很怪,非常怪。