链表题目

7-8 单向链表3 (10 分)

编程实现:输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:

输入一个正整数 n(0<n<=9)和一组(n个)升序的整数,建立单向链表,再输入一个整数 x,把 x 插入到这组数据中,使该组数据仍然有序。

输入输出示例:括号内为说明

输入样例:

4               (repeat=4) 
5               (数据的个数n=5)
1 2 4 5 7       (5个有序整数)
3               (待插入整数x=3)
4               (数据的个数n=4)
1 2 5 7	        (4个有序整数)
-10             (待插入整数x=-10)
3               (数据的个数n=3)
1 2 4	        (3个有序整数)
100             (待插入整数x=100)
5               (数据的个数n=5)
1 2 4 5 7       (5个有序整数)
4               (待插入整数x=4)

输出样例:

size=6:1 2 3 4 5 7 
size=5:-10 1 2 5 7 
size=4:1 2 4 100 
size=6:1 2 4 4 5 7
#include<iostream>
using namespace std;
struct Node{
	int data;
	struct Node *next;
};
struct Node *Create(int n)
{
	Node *p=NULL,*q=NULL,*head=NULL;
	for(int i=0;i<n;i++)
	{
		q=new Node;//新建一个Node给q
		q->next=NULL;//先让它的next为NULL,比较安全
		cin>>q->data;
		if(head==NULL)
		{
			head=p=q;//让三个指针都先指向第一个Node 
		}
		else
		{
			p->next=q;//q起到的作用就是把链表串起来
			p=q;//将p移到链表的下一个位置上,以便下一次的串联 
		}
	}
	return head;//返回头节点 
}
struct Node *Insert(Node *head,int x)//插入数x 
{
	Node *p,*q;
	int flag=0;
	p=head;
	if(head==NULL) return head;
	q=new Node;
	q->data=x;
	q->next=NULL;
	if(p->data>x)//如果x的值小于链表中的第一个数 
	{
		q->next=p;
		head=q;//如果替换了第一个数,记得要修改头节点
		return head; 
	} 
	while(p->next!=NULL)
	{
		if(p->data<=x&&p->next->data>x)
		{
			q->next=p->next;
			p->next=q;
			flag=1;
			break;
		}
		p=p->next;//指向下一个,往下一项移动 
	}
	if(flag==0)
		p->next=q;
	return head;
}
int main()
{
	int repeat;
	cin>>repeat;
	Node *head,*p;
	for(int i=0;i<repeat;i++)
	{
		int n;
		cin>>n;
		int b;
		head=Create(n);	
		cin>>b;
		head=Insert(head,b);
		p=head;
		cout<<"size="<<n+1<<":";
		cout<<p->data;
		p=p->next;
		while(p!=NULL)
		{
			cout<<" "<<p->data;
			p=p->next;
		}
        cout<<endl;
}
	return 0;
}

7-12 单链表基本操作 (5 分)

请编写程序实现单链表插入、删除结点等基本算法。给定一个单链表和一系列插入、删除结点的操作序列,输出实施上述操作后的链表。单链表数据域值为整数。

输入格式:

输入第1行为1个正整数n,表示当前单链表长度;第2行为n个空格间隔的整数,为该链表n个元素的数据域值。第3行为1个正整数m,表示对该链表施加的操作数量;接下来m行,每行表示一个操作,为2个或3个整数,格式为0 k d或1 k。0 k d表示在链表第k个结点后插入一个数据域值为d的结点,若k=0则表示表头插入。1 k表示删除链表中第k个结点,此时k不能为0。注:操作序列中若含有不合法的操作(如在长度为5的链表中删除第8个结点、删除第0个结点等),则忽略该操作。n和m不超过100000。

输出格式:

输出为一行整数,表示实施上述m个操作后的链表,每个整数后一个空格。输入数据保证结果链表不空。

输入样例:

5
1 2 3 4 5
5
0 2 8
0 9 6
0 0 7
1 0 
1 6

输出样例:

7 1 2 8 3 5 
#include<iostream>
using namespace std;
struct Node{
	int data;
	struct Node *next;
};
struct Node *Create(int n)//创建链表
{
	Node *p=NULL,*q=NULL,*head=NULL;
	for(int i=0;i<n;i++)
	{
		q=new Node;//新建一个Node给q
		q->next=NULL;//先让它的next为NULL,比较安全
		cin>>q->data;
		if(head==NULL)
		{
			head=p=q;//让三个指针都先指向第一个Node 
		}
		else
		{
			p->next=q;//q起到的作用就是把链表串起来
			p=q;//将p移到链表的下一个位置上,以便下一次的串联 
		}
	}
	return head;//返回头节点 
}

struct Node *Insert(Node *head,int k,int b)//在链表第k个节点后插入一个数值为d的节点 
{
	Node *p,*q;
	p=head;
	if(head==NULL) return head;
	q=new Node;
	q->data=b;
	q->next=NULL;
	if(k==0)
	{
		q->next=p;
		head=q;
		return head;
	}
	if(k!=0)
	{
		for(int i=1;i<k;i++)
			p=p->next;
		q->next=p->next;
		p->next=q;
		return head;
	}
}

struct Node *Delete(Node *head,int k)//删除某个节点 
{
	Node *p;
	p=head;
	if(head==NULL) return head;
	if(k==1)
	{
		p=p->next;
		head=p;
		return head;
	}
	else
	{
		while(k-2)
		{
			p=p->next;
			k--;
		}
		p->next=p->next->next;
		return head;
	}
}
int main()
{
	int n;
	Node *p,*head;
	cin>>n;//为单链表的长度
	head=Create(n);
	int m;//为对链表的操作数量
	cin>>m;
	int count=n; 
	for(int i=0;i<m;i++)
	{
		int a;
		cin>>a;
		if(a==0)
		{
			int k,b;
			cin>>k>>b;
			if(k>count)
				continue;
			count++;
			head=Insert(head,k,b);
			p=head;
		}
		else if(a==1)
		{
			int k;
			cin>>k;
			if(k>count||k==0)
				continue;
			count--;
			head=Delete(head,k);
			p=head;
		}
	}
	p=head;
	while(p!=NULL)
		{
			cout<<p->data<<" ";
			p=p->next;
		} 
} 

7-13 链表操作-插入、查找和删除 (100 分)

请编写创建链表和输出链表的函数。对于以下数据结点的结构定义,
针对带头结点的链表,请编程完成以下功能。
struct LNode{
int data;                  //数据域
struct LNode *next;        //指针域
};
struct LNode *head;            //头指针
输入数据包含若干组命令和数据,一组数据中的第1个字符代表命令,
接下来的是该命令需要的数据。
(1)如果命令是I,功能为创建空链表,对应函数:void List_Init(head);
(2)如果命令是A,后跟一个整数data,功能为向链表尾部追加一个数据data,
对应函数:void List_Append(head,data);
(3)如果命令是C,后跟一个整数N,再跟N个整数,功能为向链表尾部追加N个
数据,可通过调用List_Append()函数实现;
(4)如果命令是P,功能遍历输出链表中所有数据,数据间用一个空格分隔,对应
函数:void List_print(head),如果链表未建立,输出“List not defined!”,
如果链表为空输出:“List is empty!”。

以上为上一题目的内容,在此基础上,增加设计如下功能:

(5)如果命令是N,后跟一个整数n和d,功能为向链表的第n个位置插入数据d,
可通过调用List_Insert(head,n,d)函数实现;
(6)如果命令是F,后跟一个整数d,功能为在链表查找数据d,返回其位序,若
找不到返回-1。可通过调用List_Find(head,d)函数实现;
(7)如果命令是D,后跟一个整数n,功能为删除链表第n个位置的数据,可通过
调用List_Delete(head,n)函数实现。

输入格式:

若干组命令和数据,很多命令和数据写在一起请注意识别。

输出格式:

根据输入命令输出相应内容,详见输出样例。

输入样例:

I C 5 100 200 300 400 500 P
F 500 N 3 23 N 5 31 P
D 4 P F 99
A 6 P

输出样例:

100 200 300 400 500
index:5
100 200 23 300 31 400 500
100 200 23 31 400 500
Not Found!
100 200 23 31 400 500 6

输入样例:

I A 100 A 200 A 300 C 4 400 500 600 700 P
F 800 F 500
N 4 4 N 5 5 P
D 2 D 2 D 2 P
D 2 D 2 D 2 P
D 1 D 1 P
D 1 D 1 P

输出样例:

100 200 300 400 500 600 700
Not Found!
index:5
100 200 300 4 5 400 500 600 700
100 5 400 500 600 700
100 600 700
700
List is empty!
#include<iostream>
using namespace std;
struct Node{
	int data;
	struct Node *next;
};
struct Node *head;//在外部声明,则后面函数中可以直接用void不用struct 
void List_Init(Node *&head)//新建一个空链表 
{
	head=new Node;
	head->next=NULL;
}
void List_Append(Node *head,int data)//向链表的尾部追加一个数据data 
{
	Node *p,*q;
	p=head;
	q=new Node;
	q->data=data;
	q->next=NULL;
	while(p->next!=NULL){
		p=p->next;
	}
	p->next=q;
}
void List_print(Node *head)//遍历输出链表中的所有数据,如果链表未建立,输出"List not defined!"如果链表为空输出:"List is empty!" 
{
	Node *p;
	if(head==NULL){
		cout<<"List not defined!"<<endl;
		return;
	}
	if(head->next==NULL){
		cout<<"List is empty!"<<endl;
		return;
	}
	p=head->next;//因为这是一个带头结点的链表,所以head实际上是没有数的,它指向的才存了第一个数 
	cout<<p->data;
	p=p->next;
	while(p!=NULL){
		cout<<' '<<p->data;
		p=p->next;
	}
	cout<<endl;
}
void List_Insert(Node *head,int n,int d)//向链表的第n个位置插入数据d 
{
	int i;
	Node *p,*q;
	q=new Node;
	q->data=d;
	q->next=NULL;
	p=head;
	for(i=1;i<n;i++)p=p->next;
	q->next=p->next;
	p->next=q;
}
int List_Find(Node *head,int d)//在链表中查找数据d,并返回其位序,如果找不到则返回-1 
{
	int cnt=1;
	Node *p;
	p=head->next;
	while(p!=NULL){
		if(p->data==d)return cnt;
		p=p->next;
		cnt++;
	}
	return -1;
}
void List_Delete(Node *head,int n)//删除链表第n个位置的数据 
{
	Node *p,*q;
	int i;
	p=head;
	q=p->next;
	for(i=1;i<n;i++){
		if(p!=NULL)p=p->next;
	}
	if(p==NULL || p->next==NULL)return;
	q=p->next;
	p->next=p->next->next;
	delete q;
}

int main()
{
	head=NULL;
	char c;
	int i,n,N,data;
	while(cin>>c){
		if(c=='I')List_Init(head);
		if(c=='A'){
			cin>>data;
			List_Append(head,data);
		}
		if(c=='C'){
			cin>>N;
			for(i=0;i<N;i++){
				cin>>data;
				List_Append(head,data);
			}
		}
		if(c=='P')List_print(head);
		if(c=='N'){
			cin>>n>>data;
			List_Insert(head,n,data);
		}
		if(c=='F'){
			cin>>data;
			if(List_Find(head,data)==-1)cout<<"Not Found!"<<endl;
			else cout<<"index:"<<List_Find(head,data)<<endl;
		}
		if(c=='D'){
			cin>>n;
			List_Delete(head,n);
		}
	}
	return 0;
}
  • 若已建立下面的链表结构,指针 pq 分别指向图中所示结点,则不能将 q 所指结点插入到链表末尾的语句是(C )。

1.jpg

A.

q->next = NULL;
p = p->next; 
p->next = q;

B.

p = p->next; 
q->next = p->next;
p->next = q;

C.

p = p->next; 
q->next = p;
p->next = q;

D.

p = (*p).next; 
(*q).next = (*p).next;
(*p).next = q;

需要分配较大空间,插入和删除不需要移动元素的线性表,其存储结构是(B)。

A.单链表

B.静态链表

C.线性链表

D.顺序存储结构

  • 顺序存储和链式存储没有优劣之分,根据算法要求灵活使用,但链式存储结构比顺序存储结构能更方便地表示各种逻辑结构

  • 对于一个线性表既要求能够进行较快速地插入和删除,又要求存储结构能反映数据之间的逻辑关系,则应该用(链式存储方式 )。

  • ‘静态链表需要分配较大的连续空间,插入和删除不需要移动元素

  • 若用单链表来表示队列,则应该选用带尾指针的循环链表

  • 删除最后一个链表元素时,就算设置尾指针,也无法删除最后一个节点,也只能从头结点往后遍历,删除最后一个节点,时间复杂度为O(n)

  • 设对n(n>1)个元素的线性表的运算只有4种:删除第一个元素;删除最后一个元素;在第一个元素之前插入新元素;

  • 在最后一个元素之后插入新元素,则最好使用(只有头结点指针没有尾结点指针的循环双链表)。

  • 需要分配较大空间,插入和删除不需要移动元素的线性表,其存储结构为( 静态链表)。

单链表中,增加一个头结点的目的是(C )

A.使单链表至少有一个结点。

B.标识表结点中首结点的位置。

C.方便运算的实现。

D.说明单链表是线性表的链式存储

解析:(1) 对带头结点的链表,在表的任何结点之前插入结点或删除表中任何结点,所要做的都是修改前一结点的指针域,因为任何元素结点都有前驱结点。若链表没有头结点,则首元素结点没有前驱结点,在其前插入结点或删除该结点时操作会复杂些。 (2) 对带头结点的链表,表头指针是指向头结点的非空指针,因此空表与非空表的处理是一样的。

2-1

线性表若采用链式存储结构时,要求内存中可用存储单元的地址 B

A 必须是连续的
B 连续或不连续都可以
C 部分地址必须是连续的
D 一定是不连续的

2-2

线性表L在什么情况下适用于使用链式结构实现? A

A 需不断对L进行删除插入
B 需经常修改L中的结点值
C L中含有大量的结点
D L中结点结构复杂

2-3

链表不具有的特点是: B

A 插入、删除不需要移动元素
B 方便随机访问任一元素
C 不必事先估计存储空间
D 所需空间与线性长度成正比

2-7

可以用带表头附加结点的链表表示线性表,也可以用不带头结点的链表表示线性表,前者最主要的好处是(B)。 (1分)

A 可以加快对表的遍历
B 使空表和非空表的处理统一
C 节省存储空间
D 可以提高存取表元素的速度

2-8

在单链表中,要删除某一指定结点,必须先找到该结点的(A)。 (1分)

A 直接前驱
B 自身位置
C 直接后继
D 直接后继的后继

2-9

以下关于链式存储结构的叙述中,(C)是不正确的。 (1分)

A 结点除自身信息外还包括指针域,因此存储密度小于顺序存储结构
B 逻辑上相邻的结点物理上不必邻接
C 可以通过计算直接确定第i个结点的存储地址
D 插入、删除运算操作方便,不必移动结点

以下结构类型可用来构造链表的是(B)。

A.struct aa{ int a;int * b;};

B.struct bb{ int a;bb * b;};

C.struct cc{ int * a;cc b;};

D.struct dd{ int * a;aa b;};

链表要有一个next,next的类型要与结构体的类型一致

2-13

关于delete运算符的下列描述中,(C)是错误的。

A.它必须用于new返回的指针;

B.使用它删除对象时要调用析构函数;

C.对一个指针可以使用多次该运算符;

D.指针名前只有一对方括号符号,不管所删除数组的维数。

2-14

以下程序中,new语句干了什么。(C)

int** num;

num = new int* [20];

A.分配了长度为20的整数数组空间,并将首元素的指针返回。

B.分配了一个整数变量的空间,并将其初始化为20。

C.分配了长度为20的整数指针数组空间,并将num[0]的指针返回。

D.存在错误,编译不能通过。

关于new运算符的下列描述中,(D)是错误的。

A.它可以用来动态创建对象和对象数组;

B.使用它创建的对象或对象数组可以使用运算符delete删除;

C.使用它创建对象时要调用构造函数;

D.使用它创建对象数组时必须指定初始值

2-11

表达式 “new int”的返回值类型是?

A.int

B.int *

C.int &

D.无法确定

设void f1(int * m,long & n);int a;long b;则以下调用合法的是(B)。

A.f1(a,b);

B.f1(&a,b);

C.f1(a,&b);

D.f1(&a,&b);

posted @ 2021-06-04 20:39  小滢小滢考第一名  阅读(1161)  评论(1编辑  收藏  举报