#数据结构#第二章:链表

判断题

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(log​2n)
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;
}

发布了145 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43476037/article/details/100710207