一、 线性表的顺序表示
定义:线性表的顺序表示指的是用一组地址连续的存储单位依次存储线性表的数据元素。
1、宏定义解释
ElemType :线性表数据元素数据类型
LIST_INIT_SIZE : 线性表初始数据元素容量
Status :函数返回值(一般替换int型)
error :0
INFEASIBLE :0
OK :0
2、线性表的动态分配顺序存储结构
#define LIST_INIT_SIZE 100 //线性表存储空间的初始化分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量
typedef struct{
ElemType *elem; //存储空间基址
int length; //当前长度
int listise; //当前分配的存储容量(以sizeof(ElemType)为单位)
}SqList;
二、13个基本操作
分别是:
建立线性表,清空线性表,销毁线性表
判空线性表,判满线性表,获得当前数据元素个数
获得指定位置的数据元素,定位符合一定条件的数据元素
获得一个数据元素的前驱,获得一个元素的后继
插入数据元素,删除数据元素
遍历线性表
1、建立线性表
初始条件:一个未初始化的线性表结构体
Status InitList(SqList &L){
L.elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType)); //申请存储空间
if(!L.elem)
exit(0); //存储分配失败
L.length=0//空表的长度为0
L.list=LIST_INT_SIZE;//初始数据元素存储容量
return OK;
}
2、清空线性表
初始条件:线性表存在
操作结果:清空线性表(将当前元素个数赋值0,遍历不出任何一个元素,相当于清空线性表)
Status ClearList(SqList &L)
{
L.length=0;
return Ok;
}
3、销毁线性表
初始条件:线性表已存在
操作结果:销毁线性表
Status Destroy(SqList &L)
{
free(L.elem);
L.elem=NULL;
L.length=0;
L.listsize=0;
return OK;
}
4、判空线性表
初始条件:线性表存在
操作结果:线性表为空返回true,不为空返回false
bool ListEmpty(SqList L)//不需要对线性表的成员变量进行改变,所以不使用引用
{
return (L.length==0)?true:false;
}
5、判满线性表
初始条件:线性表存在
操作结果:若线性表已满返回true,否则返回false
bool ListFull(SqList L)
{
return (L.length==L.listsize)?true:false;
}
6、获取线性表当前元素个数
初始条件:线性表已存在
操作结果:返回线性表当前元素个数
int ListLength(SqList L)
{
return L.length;
}
7、获得指定位置的数据元素
初始条件:线性表存在
操作结果:获得指定位置的数据元素并赋值给e
Status GetElem(SqList L,int i, ElemType &e)
{
if(i<1||i>L.length)
exit(error);
e=*(L.elem+i-1);//(基址+i-1)即为第i个元素的地址
return OK;
}
8、定位元素(获得符合一定条件的数据元素的位序)
初始条件:线性表已存在
操作结果:返回L中第一个与e满足关系的元素的位序,若不存在返回0
(注意:compare()表示一个关系判定函数,满足返回值为1,否则返回值为2,使用函数指针,方便调用)
int LocateElem(SqList L,ElemType e,status(*compare (ElemType,ElemType))//后面的是函数指针,会在最后有个例子说明
{
Elem *p=L.elem;//P的初值为第一个元素的存储位置
int i=1;//i的初值为第一个元素的位序
while(i<=L.length&&!compare(*p++,e))//越界或已找到满足条件的元素
//i的最大可能值为L.length+1
{
if(i<=L.length)
return i;
else
return 0;
}
}
9、返回前驱
初始条件:线性表已存在,数据元素存在前驱
操作结果:查找数据元素,若线性表中有该元素且前驱存在,将前驱拷贝给一个与数据元素数据类型相同的变量;若前驱不存在,上述变量无定义
//返回前驱,equal要提前声明
Status PriorElem(SqList L,ElemType cur_e,ElemType &pre_e)
{
int a;
a=LocateElem(L,cur_e,equal);
if(!a||a==1)
{
cout<<"查找失败"<<endl;
return error;
}
pre_e=*(L.elem+a-2);
return OK;
}
10、返回后继
初始条件:线性表已存在,数据元素存在后继
操作结果:查找数据元素,若线性表中有该元素且后继存在,将后继拷贝给一个与数据元素数据类型相同的变量;若后继不存在,上述变量无定义
Status NextElem(SqList L,ElemType cur_e,ElemType &next_e)
{
int a;
a=LocateElem(L,cur_e,equal);
if(!a||a==L.length)
{
cout<<"查找失败"<<endl;
return error;
}
next_e=*(L.elem+a);
return OK;
}
11、插入一个数据元素
初始条件:线性表存在
操作结果:在L中第i个元素之前插入新的元素e,L的长度加1
Status ListInsert(SqList &L,int i,ElemType e)
{
ElemType *newbase,*q,*p;
if(i<1||i>L.length+1)//i值不合法
return error;
if(L.length>=L.listsize) //当前存储空间已满,增加分配
{
if(!(newbase=(ElemType*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType))))
exit(0);//分配存储空间失败
L.elem=newbase;//新基址
L.listsize+=LISTINREMENT;//增加存储容量
}
q=L.elem+i-1;//q为插入位置
for(p=L.elem+L.length-1;p>=q;--p)
{ *(p+1)=*p;//给插入位置之后的元素赋值达到之后元素后移一位的效果
}
*q=e;//插入e
++L.length;
return OK;
}
12、删除元素
初始条件:线性表已存在
操作结构:删除第i个数据元素并返回其值,L的长度减1
Status ListDelete(SqList &L,int i,ElemType &e)
{
ElemType *p,*q;
if(i<1||i>L.length)//i值不合法
return error;
p=L.elem+i-1;//p为被删除元素的位置
e=*p;//被删除元素的值赋给e
q=L.elem+L.length-1;//表尾元素的位置
for(++p;p<=q;++p)
*(p-1)=*p;
L.length--;
return OK;
}
13、遍历线性表
初始条件:线性表已存在
操作结果:依次对L的每个元素使用函数f(),f()可以是输出函数,一旦操作失败,则操作失败
Status ListTraverse(SqList L, void(*f)(ElemType&))
{
ElemType *p=L.elem;
int i;
for(i=1;i<=L.length;i++)
f(*p++);
cout<<endl;
return OK;
}
二、顺序表实现的集合运算(A-B)U(B-A)
#ifndef _SQLIST_
#define _SQLIST_
// 顺序表结构
struct sqlist {
int len;
int size;
ElemType *elem;
};
// 顺序表初始化
void InitList( sqlist &L, int m )
{
L.len = 0;
L.size = m;
if ( m == 0 )
L.elem = NULL;
else
L.elem = new ElemType[ m ];
}
// 返回顺序表中序号为i的数据元素(i的合法值为1≤i<len)
bool GetElem( sqlist L, int i, ElemType &e )
{
if ( i < 1 || i > L.len )
return false;
e = L.elem[i - 1];
return true;
}
//置空顺序表
void ClearList( sqlist &L )
{
L.len = 0;
}
//销毁顺序表
void DestroyList( sqlist &L )
{
delete [] L.elem ;
L.size = L.len = 0;
L.elem = NULL;
}
//判断顺序表是否为空表
bool ListEmpty( sqlist L )
{
if ( L.len == 0 )
return true;
else
return false;
}
//求顺序表的长度
int ListLength( sqlist L )
{
return L.len;
}
// 函数从第一个位置起查找与e匹配的数据元素,若存在返回它的位置
int LocateElem( sqlist &L, ElemType &e, bool( *compare ) ( ElemType &a, ElemType &b) )
{
ElemType *p = L.elem;
int i = 1;
while ( i <= L.len && ! compare( *p, e) )
{
p++;
i++;
}
if ( i <= L.len )
return i;
return 0;
}
// 在顺序表的第i个数据元素之前插入新的数据元素e(i的合法值为1≤i≤len+1)。
bool ListInsert( sqlist &L, int i, ElemType &e )
{
if ( i < 1 || i > L.len + 1 )
return false; // 插入位置i值不合法。
if ( L.len >= L.size )
{ // 表满则扩展空间。
ElemType *newbase;
newbase = new ElemType[ L.size + 10 ];
if ( ! newbase )
return false;
for ( int j = 0; j < L.len; j++ )
newbase[j] = L.elem[j];
delete L.elem;
L.elem = newbase;
L.size += 10;
}
ElemType *p,*q;
q = &L.elem [ i - 1 ]; // q为插入位置指针
for ( p = &L.elem[ L.len - 1 ]; p >= q; --p )
*( p + 1 ) = *p; // 插入位置及之后的数据元素后移
*q = e; // 插入e
L.len++; // 表长增1
return true;
}
// 在顺序表的表尾插入新的数据元素e
bool ListAppend( sqlist &L, ElemType &e )
{
if ( L.len >= L.size )
{ //表满则扩展空间
ElemType *newbase = new ElemType[ L.size + 10 ];
if ( ! newbase )
return false;
for ( int j = 0; j < L.len; j++ )
newbase[ j ] = L.elem[ j ];
delete L.elem;
L.elem = newbase;
L.size += 10;
}
L.elem[ L.len++ ] = e; // 尾部插入e, 表长增1
return true;
}
//函数在顺序表中删除第i个数据元素并用e返回(i的合法值为1≤i≤Len)
bool ListDelete( sqlist &L, int i, ElemType &e )
{
if ( i < 1 || i > L.len )
return false; // 删除位置i值不合法
ElemType *p,*q;
p = &L.elem[ i - 1 ]; // p为删除位置指针
e = *p; // 被删除数据元素的值赋给e
q = L.elem + L.len - 1; // q为表尾位置指针
for ( ++p; p <= q; p++ )
*( p - 1 ) = *p; // 被删数据元素之后的数据元素前移
L.len--; // 表长减1
return true;
}
// 遍历:依次对顺序表中的每个数据元素visit()一次且仅一次。
void ListTraverse( sqlist &L, void( *visit ) ( ElemType &e ) )
{
ElemType *p = L.elem;
for ( int i = 0; i < L.len; i++ )
visit( *p++ );
}
#endif
//==============================================
// 集合运算 (A - B) U (B - A)
//----------------------------------------------
#include <iostream>
typedef char ElemType;
#include "SqList.h"
using namespace std;
//匹配LocateElem函数中的函数参量compare,数据元素相等的条件由数据元素类型决定
bool equal( ElemType &a, ElemType &b )
{
if ( a == b )
return true;
else
return false;
}
//匹配ListTrverse函数中的函数参量Visit,输出的项数由数据元素类型决定
void print( ElemType &e )
{
cout << e;
}
// 使用顺序表实现集合运算(A-B)U(B-A),即找出两个集合中所有不同的元素
void Differrence( sqlist &la, sqlist lb )
{
int i;
int lblen = ListLength( lb );
for ( i = 1; i <= lblen; i++ )
{ // 逐一读入B表的数据到A表中查找,若存在则从A表中删除,否则,插入至A表。
char e;
GetElem( lb, i, e ); // 在顺序表中取值效率较单链表高,时间复杂度为O(1)。
int k = LocateElem( la, e, equal );
if ( k )
ListDelete( la, k, e );//在顺序表中删除一个数据元素须移动n/2个数据元素,时间复杂度为O(n)。
else
ListAppend( la, e ); // 在顺序表表尾插入数据元素无须移动数据元素,时间复杂度为O(1)。
}
}
// 建立以顺序表存储表示的集合
void CreateList( sqlist &la, int &n )
{
char e;
for ( int i = 0; i < n; i++ )
{
cin >> e;
ListAppend( la, e );
}
}
int main()
{
cout << "---此程序实现集合运算(A-B)U(B-A)---" << endl << endl;
cout << "《线性表抽象数据类型用顺序表实现,数据元素类型是字符型》";
cout << endl << endl;
sqlist la, lb;
int n, m, size;
cout << "请输入A表的初始空间大小:" ;
cin >> size;
InitList( la, size);
cout << "请输入集合A中元素的个数:" ;
cin >> n;
cout << "请输入" << n << "个数据元素至集合A:" << endl;
CreateList( la, n );
cout << endl << "请输入B表的初始空间大小:" ;
cin >> size;
InitList( lb, size );
cout << "请输入集合B中元素的个数:" ;
cin >> m;
cout << "请输入"<< m << "个数据元素至集合B:" << endl;
CreateList( lb ,m );
Differrence( la, lb );
cout << endl;
cout << "运算后的结果是:" << endl;
ListTraverse( la, print );
cout << endl << endl;
DestroyList( la );
DestroyList( lb );
system( "pause" );
return 0;
}