一、判断题
1-1 反了
1-2
链表是链式存储结构,表中元素的地址不一定连续
1-3 O(n)或O(m) 看你把谁连在后面
二、选择题
带头结点的单链表,头结点是固定存在的,其next域指向链表的第一个元素,如果next域为空,说明链表中没有元素,即为空。
前一链表的最大元素也比后一链表的最小元素小
其他三项均为链表的特点
遍历长度为m的链表找到其为元素,时间复杂度为O(m)
注意与带头结点的相比较
2-18
可以用带表头附加结点的链表表示线性表,也可以用不带头结点的链表表示线性表,前者最主要的好处是(B)。(2分)
A.可以加快对表的遍历
B.使空表和非空表的处理统一
C.节省存储空间
D.可以提高存取表元素的速度
三、编程题
6-2 单链表元素定位 (12分)
本题要求在链表中查找第一个数据域取值为x的节点,返回节点的位序。L是一个带头结点的单链表,函数ListLocate_L(LinkList L, ElemType x)
要求在链表中查找第一个数据域取值为x的节点,返回其位序(从1开始),查找不到则返回0。例如,原单链表各个元素节点的元素依次为1,2,3,4,则ListLocate_L(L, 1)
返回1,ListLocate_L(L, 3)
返回3,而ListLocate_L(L, 100)
返回0。
函数接口定义:
int ListLocate_L(LinkList L, ElemType x);
其中 L
是一个带头节点的单链表。 x
是一个给定的值。函数须在链表中查找第一个数据域取值为x
的节点。若找到则返回其位序(从1开始),找不到则返回0。
裁判测试程序样例:
//库函数头文件包含
#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;
}
//下面是需要实现的函数的声明
int ListLocate_L(LinkList L, ElemType x);
int main()
{
LinkList L;
int n;
int x,k;
scanf("%d",&n); //输入链表中元素个数
if(ListCreate_L(L,n)!= OK) {
printf("表创建失败!!!\n");
return -1;
}
scanf("%d",&x); //输入待查找元素
k=ListLocate_L(L,x);
printf("%d\n",k);
return 0;
}
/* 请在这里填写答案 */
输入样例:
4
1 2 3 4
1
输出样例:
1
答案:
//思路:创建一个指针,遍历整个链表,直到找到该元素,否则指针后移
//注意:找到则返回一,否则返回零,要考虑空表的情况
int ListLocate_L(LinkList L, ElemType x)
{
LNode* p;
p = L->next;
if(!p) return ERROR;//空表
int i=1;
while (p && p!=NULL)//遍历
{
if(p->data==x)//找到
{
return i;
}
i++;//记录位序
p = p->next;
}
return 0;
}
6-3 删除单链表中最后一个与给定值相等的结点 (10分)
本题要求在链表中删除最后一个数据域取值为x的节点。L是一个带头结点的单链表,函数ListLocateAndDel_L(LinkList L, ElemType x)
要求在链表中查找最后一个数据域取值为x的节点并将其删除。例如,原单链表各个节点的数据域依次为1 3 1 4 3 5,则ListLocateAndDel_L(L,3)
执行后,链表中剩余各个节点的数据域取值依次为1 3 1 4 5。
函数接口定义:
void ListLocateAndDel_L(LinkList L, ElemType x);
其中 L
是一个带头节点的单链表。 x
是一个给定的值。函数须在链表中定位最后一个数据域取值为x的节点并删除之。
裁判测试程序样例:
//库函数头文件包含
#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
#define NULL 0
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;
for (int i=1;i<=n;i++){
curPtr=(LNode*)malloc(sizeof(LNode));
if(!curPtr)exit(OVERFLOW);
scanf("%d",&curPtr->data);
curPtr->next=NULL;
rearPtr->next=curPtr;
rearPtr=curPtr;
}
return OK;
}
//链表输出函数
void ListPrint_L(LinkList L)
{
LNode *p=L->next;
if(!p){
printf("空表");
return;
}
while(p!=NULL)
{
if(p->next!=NULL)
printf("%d ",p->data);
else
printf("%d",p->data);
p=p->next;
}
}
//下面是需要实现的函数的声明
void ListLocateAndDel_L(LinkList L, ElemType x);
int main()
{
LinkList L;
int n;
int x;
scanf("%d",&n); //输入链表中元素个数
if(ListCreate_L(L,n)!= OK) {
printf("表创建失败!!!\n");
return -1;
}
scanf("%d",&x); //输入待查找元素
ListLocateAndDel_L(L,x);
ListPrint_L(L);
return 0;
}
/* 请在这里填写答案 */
输入样例:
6
1 3 1 4 3 5
3
输出样例:
1 3 1 4 5
//思路:创建两个指针,一个指向当前结点,一个指向它的前驱,遍历找到链表中最后一个符合的结点以及其前驱结点,删除该结点后释放
//注意:一 空表,二 想要找的元素不存在
void ListLocateAndDel_L(LinkList L, ElemType x)
{
LNode *p,*q;
if(!L) return;
else
{
p=L->next; q=L;//q指向头结点
LNode *s=p;
while (p)
{
if(p->data==x) q=s;//记录并更新相同位置(q也是要删除位置的直接前驱)
s=p;//这两步就是不等就一直往后更新
p=p->next;
}
if(q!=L)//大概的意思就是q往后移动了,就可以删了
{
q->next=q->next->next;//执行删除
free(p);
}
}
}
7-1 两个有序链表序列的合并 (20分)
已知两个非降序链表序列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
//思路:创建三个指针,一个指向第一个链表,另一个指向第二个,第三个指向新链表,比较两个链表中元素的大小,将小的赋给指针三,指针后移
//注意:一 当两个链表中元素相同时,只需要将其中的一个赋给指针三0 二 链表为空时输出NULL
//库函数头文件包含
#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;
//链表创建函数
void ListInput_L(LinkList &L)
{
L=(LNode*)malloc(sizeof(LNode));
L->next=NULL;//建立一个带头结点的新链表
if(!L) exit(OVERFLOW);
LNode* p=L,*t;//一个尾指针,一个指向新节点的指针
int e;
scanf("%d",&e);
while(e!=-1)
{
t=(LNode*)malloc(sizeof(LNode));//开辟新空间用来存放新数据
t->data=e;
t->next=NULL;
p->next=t;
p=t;
scanf("%d",&e);
}
/*while (1)
{
int e;
scanf("%d",&e);
p->next->data=e;//error,未开辟新空间
if(e==-1) break;
p=p->next;
}
p->next=NULL;
L=p;*/
}
LinkList MergeList_L(LNode* &la,LNode* &lb)
{
LNode*pa,*pb,*pc;
LinkList lc;
pa=la->next;pb=lb->next;
lc=(LNode*)malloc(sizeof(LNode));lc->next=NULL;//合并后的新链表
if(!lc) exit(OVERFLOW);
pc=lc;
while(pa&&pb)
{
if(pa->data>=pb->data)//比较两个链表中元素的大小
{
pc->next=pb;//将小的赋给指针三
pb=pb->next;//指针后移
pc=pc->next;
}
else
{
pc->next=pa;
pa=pa->next;
pc=pc->next;
}
}
if(!pa)
{
pc->next=pb;free(la);
}
else
{
pc->next=pa;free(lb);
}
return lc;
}
//链表输出函数
void ListPrint_L(LinkList &L)
{
LNode *p=L->next;
if(!p){
printf("NULL");
return;
}
while(p!=NULL)
{
if(p->next!=NULL)
printf("%d ",p->data);
else
printf("%d",p->data);
p=p->next;
}
}
int main()
{
LinkList La,Lb,Lc;
ListInput_L(La);
ListInput_L(Lb);
Lc=MergeList_L(La,Lb);
ListPrint_L(Lc);
return 0;
}