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;
}
- 若已建立下面的链表结构,指针 p、q 分别指向图中所示结点,则不能将 q 所指结点插入到链表末尾的语句是(C )。
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);