目录
2、函数 Status GetElem(SqList L, int i, ElemType &e) ;
3、函数Status ListInsert( SqList &L, int i, ElemType e );
这篇文章是我开始系统学习算法时为记录学习过程写的,比较适合小白,大佬请跳过。不当之处请大家批评指正。
题目描述
题目:
有两个集合A和B分别用两个线性表LA和LB表示。求一个新的集合 A=A∪B。
输入:两个集合
输出:按照要求合并后的集合。
前置代码:
#include <stdio.h>
#include <stdlib.h>
#define LIST_MAX_SIZE 100 //空间初始大小
#define OK 1
#define ERROR 0
typedef int ElemType; //元素的数据类型
typedef int Status; //状态。函数返回值
typedef struct {
// ElemType elem[ LIST_MAX_SIZE ]; // 存储空间
ElemType * elem; // 存储空间
int length; // 当前元素个数
int listsize; // 能够保存的最大元素数量
} SqList;
// 以下为函数原型
Status InitList( SqList & );
Status ListInsert( SqList &, int, ElemType ); //这是需要你编写的基本操作
Status GetElem( SqList, int, ElemType & ); //这是需要你编写的基本操作
int ListLength( SqList ); //这是需要你编写的基本操作
Status ListTraverse( SqList &, void (*)( ElemType ) );
void ListUnion( SqList &, SqList );
void out( ElemType );
int equal(ElemType, ElemType );
Status LocateElem(SqList, ElemType, Status (*)(ElemType,ElemType));
// 以下为函数定义
Status InitList( SqList & L ) // 建立一个空的线性表 L
{
L.elem = (ElemType *)malloc(LIST_MAX_SIZE*sizeof(ElemType));
// if ( !L.elem ) exit(-1); // 失败则终止程序
L.length = 0; // 空表长度为0
L.listsize = LIST_MAX_SIZE;
return OK;
}
Status ListTraverse( SqList &L, void (*visit)( ElemType ) )
{ // 依次对L的每个元素调用函数visit()。若visit()失败,则操作失败
int i, L_len = ListLength( L );
ElemType e;
for ( i = 1; i <= L_len; i++ ) {
GetElem(L, i, e);
(*visit)( e );
}
return OK;
}
int equal(ElemType x, ElemType y)
{ return x==y;
}
Status LocateElem( SqList L, ElemType e,
Status (*compare)(ElemType,ElemType) )
{ //在L中查找与元素 e 满足compare() 的第 1 个元素
//返回 L 中第 1 个与 e 满足关系compare( ) 的元素的位序
int i = 1;
ElemType * p;
while ( i<=L.length ) //
if ( (*compare)(e,L.elem[i-1]) ) break;
else i++;
if ( i <= L.length ) return i; // 找到 e,返回位序i
else return 0; //若没有找到,则返回0
}
void out( ElemType e )
{ printf("%d,", e);
}
void ListUnion( SqList &La, SqList Lb ) //求 A=A∪B
{ int La_len, Lb_len, i;
ElemType e;
La_len = ListLength( La ); // 求线性表的长度
Lb_len = ListLength( Lb );
for ( i = 1; i <= Lb_len; i++ ) {
GetElem(Lb, i, e); // 取Lb中第i个数据元素赋给e
if ( !LocateElem( La, e, equal ) )
ListInsert ( La, ++La_len, e ); // La中不存在和 e 相同的数据元素,则插入
}
}
int main()
{ SqList La, Lb;
int n, i;
ElemType e;
InitList( La );
InitList( Lb );
scanf("%d", &n); //读入集合A
for ( i=0; i<n; i++ )
{ scanf("%d", &e);
ListInsert( La, i+1, e );
}
scanf("%d", &n); //读入集合B
for ( i=0; i<n; i++ )
{ scanf("%d", &e);
ListInsert( Lb, i+1, e );
}
printf("Output La:");
ListTraverse( La, out );
printf("\nOutput Lb:");
ListTraverse( Lb, out );
ListUnion( La, Lb );
printf("\nResult La:");
ListTraverse( La, out );
printf("\n");
return OK;
}
问题分析
首先分析一下前置代码:
代码头部:
我们先看一下代码头部的信息
#include <stdio.h>
#include <stdlib.h>
#define LIST_MAX_SIZE 100 //定义最大集合空间的大小
#define OK 1
#define ERROR 0
typedef int ElemType; //元素的数据类型 这里专门把int换一个名的目的是
//有些题的集合元素不是int类型,到时候可以一键更换类型。
typedef int Status; //状态,函数返回值
typedef struct //结构体设置
{
ElemType * elem; // 存储空间
int length; // 当前元素个数
int listsize; // 能够保存的最大元素数量
} SqList;
main函数:
分析前置代码时,我们最好先读一下main函数,搞明白代码大体在做一件什么事情,把做事的流程搞清楚,再去读具体各部分怎么实现的代码。
int main()
{ SqList La, Lb; //建立线性表La,Lb
int n, i;
ElemType e;
InitList( La ); //初始化线性表La
InitList( Lb ); //初始化线性表Lb
scanf("%d", &n); //读入集合A
for ( i=0; i<n; i++ )
{ scanf("%d", &e);
ListInsert( La, i+1, e ); //向线性表La中逐个插入元素
}
scanf("%d", &n); //读入集合B
for ( i=0; i<n; i++ )
{ scanf("%d", &e);
ListInsert( Lb, i+1, e ); //向线性表Lb中逐个插入元素
}
printf("Output La:"); //输出线性表La
ListTraverse( La, out );
printf("\nOutput Lb:"); //输出线性表Lb
ListTraverse( Lb, out );
ListUnion( La, Lb ); //合并线性表La,Lb
printf("\nResult La:"); //输出合并后的线性表La
ListTraverse( La, out );
printf("\n");
return OK;
}
各子函数:
接着我们来看一下各个函数具体怎么实现:
1、初始化线性表的函数
Status InitList( SqList & L ) // 建立一个空的线性表 L
{
L.elem = (ElemType *)malloc(LIST_MAX_SIZE*sizeof(ElemType)); //分配存储空间
// if ( !L.elem ) exit(-1); // 失败则终止程序
L.length = 0; // 空表长度置为0
L.listsize = LIST_MAX_SIZE; //设置表的最大容量
return OK; //成功建立
}
2、 输出线性表的函数:
void out( ElemType e )
{ printf("%d,", e); //输出表中所存元素
}
3、判断两元素是否相等的函数
int equal(ElemType x, ElemType y)
{ return x==y; //若相等,返回1,否则返回0
}
4、合并两集合的函数
void ListUnion( SqList &La, SqList Lb ) //求 A=A∪B
{ int La_len, Lb_len, i;
ElemType e;
La_len = ListLength( La ); // 求线性表的长度
Lb_len = ListLength( Lb );
for ( i = 1; i <= Lb_len; i++ )
{
GetElem(Lb, i, e); // 取Lb中第i个数据元素赋给e
if ( !LocateElem( La, e, equal ) ) //寻找La中是否存在和e相同的数据元素
ListInsert ( La, ++La_len, e ); // 若不存在,则把e插入La中
}
}
5、寻找L中是否存在和e相同的元素
Status LocateElem( SqList L, ElemType e, Status (*compare)(ElemType,ElemType) )
{
int i = 1;
ElemType * p;
while ( i<=L.length ) //从头开始遍历L集合中的元素
if ( (*compare)(e,L.elem[i-1]) ) break; //如果找到了和e相同的元素,立刻退出
else i++; //否则继续遍历
if ( i <= L.length ) return i; // 若i小于集合容量,说明是找到了和e相同的元素后退出的,
//此时返回位序i
else return 0; //若没有找到,则返回0
}
6、输出集合元素的函数
Status ListTraverse( SqList &L, void (*visit)( ElemType ) )
{ // 其实相当于输出操作。可以看main函数里对此函数的使用,是和out函数结合了一下
int i, L_len = ListLength( L );
ElemType e;
for ( i = 1; i <= L_len; i++ ) //在 L集合的容量范围内遍历
{
GetElem(L, i, e); //得到每一个元素
(*visit)( e ); //输出每一个元素
}
return OK;
}
下面我们需要考虑的是怎么编写空着的三个函数
解题方法
1、函数int ListLength( SqList );
这个函数的编写是最简单的,因为定义结构体时已经设计了长度这个成员,所以直接用即可。
int ListLength(SqList L) //求集合容量
{
return L.length; //直接利用结构体里的length
}
2、函数 Status GetElem(SqList L, int i, ElemType &e) ;
我们可以看到,上述预置函数分析里的子函数6“输出集合元素的函数”里有用到这个函数。
它是从i=1遍历到i=L_len,逐个输出集合中的元素。
我们知道,结构体读入时是从i=0开始的,所以我们取用元素并将它赋给e时需要用下标[i-1]。
Status GetElem(SqList L, int i, ElemType &e) //将集合里的某元素赋给e
{
e=L.elem[i-1]; //把集合里的某元素赋给e
}
3、函数Status ListInsert( SqList &L, int i, ElemType e );
往集合中插入元素的函数。插入时,把插入元素目标位置及之后的位置上的元素都往后移动1个,再把该元素插到目标位置。
注意位置和下标的关系。
Status ListInsert( SqList &L, int i, ElemType e )
{ //在顺序线性表L中第 i (1≤i≤L.length+1)个位置之前插入元素e
int j;
for(j=L.length;j>=i;j--) //把第i个元素及以后的元素逐一往后移动
{
L.elem[i]=L.elem[i-1]; //注意:元素从位置1开始,但下标从0开始
}
L.elem[i-1]=e; //在第i个位置插入该元素(下标比位置少1)
L.length++; //插入后集合容量增1
}
总结
1、通过这道题,我们学会了怎样读、分析前置代码。从总体功能入手,理清总体思路,再看具体实现。从包含函数最多的函数开始读,先抓函数的流程和功能。
2、解决要编写的函数时,我们从它的功能入手,对照着其他引用过他们的函数分析,从而完成编写。编写过程中一定要注意细节!!比如下标的问题。
3、我们可以多分析一下线性表的使用,把线性表常用函数的功能及实现代码熟记于心。