算法2-1:集合union
题目描述
假设利用两个线性表LA和LB分别表示两个集合A和B(即:线性表中的数据元素即为集合中的成员),现要求一个新的集合A=A∪B。这就要求对线性表做如下操作:扩大线性表LA,将存在于线性表LB中而不存在于线性表LA中的数据元素插入到线性表LA中去。只要从线性表LB中依次取得每个元素,并依值在线性表LA中进行查访,若不存在,则插入之。上述操作过程可用下列算法描述之。
图:将两个列表合并的算法(C/C++描述)
上图算法中,在第8行取得集合B中的元素,然后再在第10行插入到集合A中。你的任务是先输出集合A和集合B中的元素,每个集合在一行中输出。然后每次在将集合B中的元素取出插入到集合A尾部后输出集合A中的元素。当然你的代码可以和上面的代码不一样,只要有相同的输出即可。
输入
有多组测试数据,每组测试数据占两行。第一行是集合A,第一个整数m(0<m<=100)代表集合A起始有m个元素,后面有m个整数,代表A中的元素。第二行是集合B,第一个整数n(0<n<=100)代表集合B起始有n个元素,后面有n个整数,代表B中的元素。每行中整数之间用一个空格隔开。
输出
每组测试数据输出n+2行:前两行分别输出集合A、集合B中的数据,后面n行是每次从B中取出元素插入到A尾部后的集合A。每行整数之间用一个空格隔开,每组测试数据之间用一行空行隔开。
样例输入
5 1 5 2 6 3
3 1 7 9
1 3
2 2 7
4 2 5 1 4
4 1 2 4 5
样例输出
1 5 2 6 3
1 7 9
1 5 2 6 3
1 5 2 6 3 7
1 5 2 6 3 7 9
3
2 7
3 2
3 2 7
2 5 1 4
1 2 4 5
2 5 1 4
2 5 1 4
2 5 1 4
2 5 1 4
代码
#include <iostream>
using namespace std;
class SeqList{
public:
int a[200];
int maxSize;
void Union(SeqList &c,SeqList &b);
};//定义线性表用结构体也可只是尝试类
void write(SeqList c)
{
for(int i=0;i<c.maxSize;i++)
{
cout<<c.a[i]<<" ";
}
cout<<"\n";
}//打印
void SeqList::Union(SeqList &c,SeqList &b)
{
int t;
bool x=0;
for(int i=0;i<b.maxSize;i++)
{
t=b.a[i];
x=0;
for(int j=0;j<c.maxSize;j++)
{
if(c.a[j]==t)
{
x=1;
break;
}
}
if(x==0)
{
c.a[c.maxSize]=t;
c.maxSize++;
}
write(c);
}
}//合并算法*****************************************************
int main() {
SeqList S1,S2;
int m,n;
while(cin>>m)
{
for(int i=0;i<m;i++)
{
cin>>S1.a[i];
}
S1.maxSize=m;
cin>>n;
for(int j=0;j<n;j++)
{
cin>>S2.a[j];
}
S2.maxSize=n;
write(S1);
write(S2);
S1.Union(S1,S2);
cout<<"\n";
}
return 0;
}
注:while(cin>>m)语句以输入的到空格或回车结束
算法2-2:有序线性表的有序合并
题目描述
已知线性表 LA 和 LB 中的数据元素按值非递减有序排列,现要求将 LA 和 LB 归并为一个新的线性表 LC, 且 LC 中的数据元素仍然按值非递减有序排列。例如,设LA=(3,5,8,11) ,LB=(2,6,8,9,11,15,20) 则
LC=(2,3,6,6,8,8,9,11,11,15,20)
算法描述如下:
从上述问题要求可知,LC中的数据元素或是LA中的数据元素,或是LB中的数据元素,则只要先设LC为空表,然后将LA或LB中的元素逐个插入到LC中即可。为使LC中元素按值非递减有序排列,可设两个指针 i 和 j 分别指向LA和LB中某个元素,若设 i 当前所指的元素为 a,j 所指的元素为 b,则当前应插入到 LC 中的元素 c 为 c = a < b ? a : b显然,指针 i 和 j 的初值均为1(实际写代码时往往是从 0 开始的),在所指元素插入 LC 之后,在 LA 或者 LB 中顺序后移。上述归并算法如下图:
图:有序列表有序插入算法
输入
有多组测试数据,每组测试数据占两行。第一行是集合A,第一个整数m(0<=m<=100)代表集合A起始有m个元素,后面有m个非递减排序的整数,代表A中的元素。第二行是集合B,第一个整数n(0<=n<=100)代表集合B起始有n个元素,后面有n个非递减排序的整数,代表B中的元素。每行中整数之间用一个空格隔开。
输出
每组测试数据只要求输出一行,这一行含有 m+n 个来自集合 A 和集合B 中的元素。结果依旧是非递减的。每个整数间用一个空格隔开。
样例输入
4 3 5 8 11
7 2 6 8 9 11 15 20
样例输出
2 3 5 6 8 8 9 11 11 15 20
代码
//oj答案错误50%
#include <iostream>
using namespace std;
typedef struct List{
int L[200];
int length;
}List;
void sort(List &l)
{
for(int i=0;i<l.length;i++)
{
for(int j=i+1;j<l.length;j++)
{
if(l.L[i]>l.L[j])
{
int t=l.L[i];
l.L[i]=l.L[j];
l.L[j]=t;
}
}
}
}
void write(List l)
{
for(int i=0;i<l.length;i++)
{
cout<<l.L[i]<<" ";
}
}
int main() {
int m,n,a=0,x;
List L1,L2;
cin>>m;
for(int i=0;i<m;i++)
{
cin>>L1.L[i];
}
cin>>n;
for(int j=0;j<n;j++)
{
cin>>L2.L[j];
}
List L3;
L3.length=m+n;
for(x=0;x<m;x++)
{
L3.L[x]=L1.L[x];
}
for(int y=x;y<m+n;y++)
{
L3.L[y]=L2.L[a++];
}
sort(L3);
write(L3);
cout<<endl;
return 0;
}
算法2-8~2-11:链表的基本操作
题目描述
链表是数据结构中一种最基本的数据结构,它是用链式存储结构实现的线性表。它较顺序表而言在插入和删除时不必移动其后的元素。现在给你一些整数,然后会频繁地插入和删除其中的某些元素,会在其中某些时候让你查找某个元素或者输出当前链表中所有的元素。
下面给你基本的算法描述:
图1:链表类型的定义以及获得链表元素的算法描述
图2:链表的插入算法描述
图3:链表的删除算法描述
图4:链表的创建算法描述
输入
输入数据只有一组,第一行有n+1个整数,第一个整数是这行余下的整数数目n,后面是n个整数。这一行整数是用来初始化列表的,并且输入的顺序与列表中的顺序相反,也就是说如果列表中是1、2、3那么输入的顺序是3、2、1。
第二行有一个整数m,代表下面还有m行。每行有一个字符串,字符串是“get”,“insert”,“delete”,“show”中的一种。如果是“get”或者“delete”,则其后跟着一个整数a,代表获得或者删除第a个元素;如果是“insert”,则其后跟着两个整数a和e,代表在第a个位置前面插入e;“show”之后没有整数。
输出
如果获取成功,则输出该元素;如果删除成功则输出“delete OK”;如果获取失败或者删除失败,则输出“get fail”以及“delete fail”。如果插入成功则输出“insert OK”,否则输出“insert fail”。如果是“show”则输出列表中的所有元素,如果列表是空的,则输出“Link list is empty”。注:所有的双引号均不输出。
样例输入
3 3 2 1
21
show
delete 1
show
delete 2
show
delete 1
show
delete 2
insert 2 5
show
insert 1 5
show
insert 1 7
show
insert 2 5
show
insert 3 6
show
insert 1 8
show
get 2
样例输出
1 2 3
delete OK
2 3
delete OK
2
delete OK
Link list is empty
delete fail
insert fail
Link list is empty
insert OK
5
insert OK
7 5
insert OK
7 5 5
insert OK
7 5 6 5
insert OK
8 7 5 6 5
7
代码
#include <iostream>
#include<stdlib.h>
#include<string>
using namespace std;
typedef int ElemType;
typedef struct LNode{
ElemType data;
LNode *next;
}LNode,*LinkList;
void CreateList_L(LinkList &L,int n)
{
//LinkList p;
int i;
L=new LNode;
L->next=NULL;
for(i=n;i>0;--i)
{
LNode *p=new LNode;
cin>>p->data;
p->next=L->next;
L->next=p;
}
}
bool GetElem (LinkList &L,int i,ElemType &e)
{
//第i个元素存在时赋值给e
LinkList p;
p=L->next;
int j=1;
while(p&&j<i)
{
p=p->next;
++j;
}
if(!p||j>i)
return 0;
e=p->data;
return 1;
}
bool ListInsert (LinkList &L,int i,ElemType &e)//e
{
LinkList p,s;
p=L;
int j=0;
while(p&&j<i-1)
{
p=p->next;
++j;
}
if(!p||j>i-1)
return 0;
s = (LNode*)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
return 1;
}
bool ListDelete(LinkList &L,int i,ElemType &e)
{
LinkList p,q;
p=L;
int j=0;
while (p->next&&j<i-1)
{
p=p->next;
++j;
}
if(!(p->next)||j>i-1)
{
return 0;
}
q=p->next;
p->next=q->next;
e=q->data;
return 1;
}
void OutPut(LinkList &L)
{
LinkList p;
p=L;
while (p->next!=NULL)
{
p=p->next;
cout<<p->data<<" ";
}
}
int main() {
LinkList L;
int n,m;
cin>>n;
int pos;
LinkList position;
ElemType e;
CreateList_L(L,n);
cin>>m;
string x;
while(cin>>x)
{
if(x=="insert")
{
cin>>pos;
cin>>e;
if(ListInsert(L,pos,e)==1)
{
cout<<"insert OK"<<endl;
n++;
}
else if(ListInsert(L,pos,e)==0)
{
cout<<"insert fail"<<endl;
}
}
else if(x=="show")
{
if(n==0)
cout<<"Link list is empty"<<endl;
else if(n>0)
{ OutPut(L);
cout<<endl;
}
}
else if(x=="delete")
{
cin>>pos;
if(ListDelete(L,pos,e)==1)
{
cout<<"delete OK"<<endl;
n--;
}
else if(ListDelete(L,pos,e)==0)
{
cout<<"delete fail"<<endl;
}
}
else if(x=="get")
{
cin>>pos;
if(GetElem (L,pos,e)==0)
{
cout<<"get fail"<<endl;
}
else if(GetElem (L,pos,e)==1)
{
cout<<e<<endl;
}
}
m-=1;
if(m<=0)
break;
}
//system("pause");
return 0;
}
算法2-18~2-19:双向循环链表
题目描述
双向链表是在结点中既保存了后一个结点指针又保存了前一个结点指针的链表。这种链表较单向链表而言能够快速查找某一结点的前后结点。下面给出双向链表的定义、插入以及删除算法描述。
图1:双向链表示例
(a)结点结构;(b)空的双向循环链表;(c)含有三个结点的双向循环链表
图2:双向链表的定义以及创建
双向链表在插入与删除时一定要注意其操作步骤的顺序。下面给出双向链表在插入与删除时的图示。
图3:双向链表插入与删除的图示
(a)双向链表的删除操作;(b)双向链表的插入操作
图4:双向链表的查找以及插入
图5:双向链表的删除操作
输入
输入数据只有一组,包含很多行。每行有1~3个整数。第一个整数如果是0,则表示输出双向链表中的所有元素;第一个整数如果是1,表示插入1个整数,其后跟2个整数i、e代表在第i个位置插入e;第一个整数如果是2,表示删除1个整数,其后跟1个整数i,表示删除的位置为i。
起始双向链表为空表。保证链表中每个元素不会重复,同时所有的操作都合法。
输出
当需要输出双向链表中的所有元素时输出,每次输出一行。整数间用一个空格隔开。
样例输入
1 1 2
0
1 2 7
0
2 1
0
1 2 4
1 3 5
1 2 6
0
2 3
0
样例输出
2
2 7
7
7 6 4 5
7 6 5
代码
#include <iostream>
using namespace std;
typedef int ElemType;
typedef struct DuLNode
{
ElemType data;
DuLNode *lLink;//left
DuLNode *rLink;//right
}DuLNode,*DuLinkList;
//创建双向循环链表//
class DuLList
{
private:
DuLinkList first,L;
public:
void ListCreate_DuL();
void ListShow_DuL();
bool ListInsert_DuL(int i,ElemType e);
bool ListDelete_DuL(int i,ElemType &e);
DuLinkList GetElemp_DuL(int i);
};
void DuLList::ListCreate_DuL()//传的参数是结构体的指针的引用,L是结构体指针
{
L=new DuLNode;
first=L;
L->lLink=L;
L->rLink=L;
//初始指针都指向自己
}
DuLinkList DuLList::GetElemp_DuL(int i)
{
DuLinkList p;
p=L;
int pos=0;//记录查找元素的位置
while(p->rLink!=L&&pos<i)
{
p=p->rLink;
pos++;
}
if(p->rLink==L&&pos<i)
{
return NULL;
}
return p;
}
bool DuLList::ListInsert_DuL(int i,ElemType e)
{//前插
DuLinkList p,s;
s=new DuLNode;
if(!s)
{
return 0;//无法开辟
}
p=GetElemp_DuL(i);
if(!p)
{
s->data=e;
s->rLink=L;
s->lLink=L->lLink;
L->lLink->rLink=s;
L->lLink=s;
}
if(p)
{
s->data=e;
s->rLink=p;
s->lLink=p->lLink;
p->lLink->rLink=s;
p->lLink=s;
}
return 1;
}
bool DuLList::ListDelete_DuL(int i,ElemType &e)
{
DuLinkList p,m;
p=GetElemp_DuL(i);
e=p->data;
p->rLink->lLink=p->lLink;
p->lLink->rLink=p->rLink;
free(p);
return 1;
}
void DuLList::ListShow_DuL()
{
DuLinkList p=first->rLink;
cout<<p->data<<" ";
while((p->rLink)!=L)
{
p=p->rLink;
cout<<p->data<<" ";
}
}
int main()
{
DuLList dullist;
dullist.ListCreate_DuL();
int X;
while(cin>>X)
{
if(X==0)
{
dullist.ListShow_DuL();
cout<<endl;
}
if(X==1)
{
int pos;
ElemType e;
cin>>pos;
cin>>e;
dullist.ListInsert_DuL(pos,e);
}
if(X==2)
{
int pos;
ElemType e;//将删除的元素传给e,此处无用
cin>>pos;
dullist.ListDelete_DuL(pos,e);
}
}
//system("pause");
return 0;
}
总结
1.动态开辟c语言和c++语法不同
2.注意define和typedef的区别
3.
typedef struct LNode{
ElemType data;
LNode *next;
}LNode,*LinkList;
的(*LinkList)含义,详见https://blog.csdn.net/qq_35624030/article/details/105341859
4.前插和后插区别
5.注意查找元素输出元素时查找错误的判断条件,尤其是双向或者循环链表只有一个元素时;插入元素时注意空表如何插入,附带头结点和不附带头结点区别
6.位置从1开始,线性表数组下标从0开始,链表的位置建议从0开始,便于写查找的判断条件使其和查找不到没有冲突错误