线性表属于线性结构,是最常用且最简单的一种数据结构,是有n个数据元素的有限序列,同一线性表中的元素必定具有相同特性。长度可根据需要增长或缩短,即对线性表的数据元素可以进行访问,还可以进行插入和删除等。
顺序存储与实现:
把逻辑上相邻的数据元素存储在物理也相邻的存储单元中。用一组地址连续的存储单元依次存储线性表的数据元素。只要确定的存储线性表的起始位置,线性表中任一数据元素都可随机存取,所以线性表的顺序存储是一种随机存取的存储结构。
优点是随机存取,查找速度快,且修改仅需要通过数组的下标便可访问某个特定元素并修改。缺点是插入和删除很耗费时间,效率低。
动态分配顺序存储结构:
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //初始分配增量
typedef struct{
ElemType *elem ; //线性表存储空间的基地址
int length ; //当前长度
int listsize ; //当前分配的存储容量
}SqList;
线性表所实现的一些基础功能:
Status InitList(SqList &L); //构造一个空的线性表L。 后续操作均在表已存在的基础上进行。
Status DestroyList(SqList &L); //销毁线性表 。
Status ClearList(SqList &L); //将表重置为空表 。
Status ListEmpty(SqList L); //判断是否为空表,是则返回TRUE,否则返回FALSE。
int ListLength(SqList L); //获取链表的长度,返回长度值。
Status GetElem(SqList L,int i,ElemType &e); //用e返回线性表中第i个位置元素的值。
Status PriorElem(SqList L,ElemType cur_e,ElemType &pre_e); //找元素 cur_e的前驱,用pre_e返回其前驱。
Status NextElem(SqList L,ElemType cur_e,ElemType &next_e); //找元素 cur_e的后继,用next_e返回其后继。
Status ListInsert(SqList &L,int i,ElemType e); //在线性表中第i个位置插入新的元素e。
Status ListDelete(SqList &L,int i,ElemType &e); //删除线性表中第i个位置的元素,并用e返回其值。
Status ListTraverse(SqList L); //对线性表的遍历。
具体实现:
#include <iostream>
#include <stdlib.h>
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //初始分配增量
#define TRUE 1
#define FALSE 0
#define OVERFLOW -2
typedef int Status ;
typedef int ElemType ;
typedef struct{
ElemType *elem ; //线性表存储空间的基地址
int length ; //当前长度
int listsize ; //当前分配的存储容量
}SqList;
Status InitList(SqList &L); //构造一个空的线性表L。 后续操作均在表已存在的基础上进行。
Status DestroyList(SqList &L); //销毁线性表 。
Status ClearList(SqList &L); //将表重置为空表 。
Status ListEmpty(SqList L); //判断是否为空表,是则返回TRUE,否则返回FALSE。
int ListLength(SqList L); //获取链表的长度,返回长度值。
Status GetElem(SqList L,int i,ElemType &e); //用e返回线性表中第i个位置元素的值。
Status PriorElem(SqList L,ElemType cur_e,ElemType &pre_e); //找元素 cur_e的前驱,用pre_e返回其前驱。
Status NextElem(SqList L,ElemType cur_e,ElemType &next_e); //找元素 cur_e的后继,用next_e返回其后继。
Status ListInsert(SqList &L,int i,ElemType e); //在线性表中第i个位置插入新的元素e。
Status ListDelete(SqList &L,int i,ElemType &e); //删除线性表中第i个位置的元素,并用e返回其值。
Status ListTraverse(SqList L); //对线性表的遍历。
void MergeList(SqList La,SqList Lb,SqList &Lc); //将线性表La和表Lb合并到表Lc中。
using namespace std;
int main(){
ElemType e , pre_e , next_e;
SqList L ;
InitList(L) ;
ListEmpty(L) ;
cout<<"顺序表的长度值为:"<<ListLength(L)<<endl;
cout << "输入顺序表的各个元素值:"<<endl;
for(int i=1;i<=5;i++){
int a ;
cin>>a ;
ListInsert(L,i,a);
}
// ListInsert(L,1,1);
// ListInsert(L,2,2);
// ListInsert(L,3,3);
// ListInsert(L,4,4);
// ListInsert(L,5,5);
ListTraverse(L) ;cout<<endl;
ListEmpty(L);
cout<<"此时顺序表的长度值为:"<<ListLength(L) <<endl;
GetElem(L,3,e) ;cout<<"获取第三个位置元素,用e输出:"<<e<<endl;
PriorElem(L,3,pre_e);
NextElem(L,3,next_e);
cout << "删除第3个位置的数据元素."<<endl;
ListDelete(L,3,e);
ListTraverse(L) ;cout<<endl;
}
Status InitList(SqList &L){
//线性表的初始化操作就是为表分配一个预定义大小的数组空间,并将表的当前长度设为1.
L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType)) ;
if(!L.elem)
exit (OVERFLOW) ; //exit(n)表示退出,传入的参数是程序退出时的状态码,0表示正常退出,其他表示非正常退出
L.length=0 ;
L.listsize=LIST_INIT_SIZE ;
return TRUE ;
}
Status DestroyList(SqList &L){
if(!L.elem){
cout<<"该顺序表不存在。"<<endl;
return FALSE ;
}
free(L.elem) ;
L.length=0 ;
L.listsize=0 ;
return TRUE ;
}
Status ClearList(SqList &L){
if(!L.elem){
cout<<"该顺序表不存在。"<<endl;
return FALSE ;
}
L.length=0 ;
return TRUE ;
}
Status ListEmpty(SqList L){
if(!L.elem){
cout<<"该顺序表不存在。"<<endl;
return FALSE ;
}
else if(L.length>0){
cout<<"该表不为空。"<<endl;
return FALSE ;
}
else{
cout<<"表为空。"<<endl;
return TRUE ;
}
}
int ListLength(SqList L){
if(!L.elem){
cout<<"顺序表不存在。"<<endl;
return FALSE ;
}
// int i ;
// for(i=0;i<L.length;i++);
// return i ;
//顺序表可直接返回其长度。
return L.length ;
}
Status GetElem(SqList L,int i,ElemType &e){
if(!L.elem){
cout<<"顺序表不存在。"<<endl;
}
if(i<0 || i>=L.length){
cout<<"获取位置不存在。"<<endl;
return FALSE ;
}
e=L.elem[i-1] ;
return TRUE ;
}
Status ListInsert(SqList &L,int i,ElemType e){ //在第i个位置处插入元素e 。
//事先应判断: 插入位置i 是否合法?表是否已满?
if(!L.elem){
cout<<"顺序表不存在。"<<endl;
return FALSE ;
}
if(i< 1|| i>L.length+1) {
cout<<"选择插入位置有误。"<<endl;
return FALSE ;
}
if(L.length+1>L.listsize){
ElemType *newbase ;
newbase = (ElemType *)realloc (L.elem,(L.listsize+LISTINCREMENT) * sizeof(ElemType)) ;
if(!newbase)
exit(OVERFLOW) ;
L.elem = newbase ;
L.listsize += LISTINCREMENT ;
}
ElemType *p ;
p=&L.elem[i-1] ;
for(;p<&(L.elem[L.length]);p++)
*(p+1) = *p ;
*p=e ;
L.length++ ; //不要忘了表长要加1
return TRUE ;
}
Status ListDelete(SqList &L,int i,ElemType &e){
//事先需要判断: 删除位置i 是否合法?
if(!L.elem){
cout<<"顺序表不存在。"<<endl;
return FALSE ;
}
if(i<0||i>=L.length){
cout<<"所需要删除的位置不存在。"<<endl;
return FALSE ;
}
ElemType *p ;
p=&L.elem[i-1] ;
e=*p ;
for(;p<&(L.elem[L.length]);p++)
*p = *(p+1) ;
L.length-- ; //别忘了
return TRUE ;
}
Status PriorElem(SqList L,ElemType cur_e,ElemType &pre_e){
if(!L.elem){
cout<<"顺序表不存在。"<<endl;
return FALSE ;
}
int i ;
for(i=1;i<L.length;i++){
//顺序表的第一个无前驱。
if(L.elem[i]==cur_e){
pre_e=L.elem[i-1] ;
cout<< cur_e << "的前驱是:" << pre_e <<endl;
return TRUE ;
}
}
cout<<"表中未找到所要查找的数据前驱。"<<endl;
return FALSE ;
}
Status NextElem(SqList L,ElemType cur_e,ElemType &next_e){
if(!L.elem){
cout<<"顺序表不存在。"<<endl;
return FALSE ;
}
int i ;
for(i=0;i<L.length-1;i++){
//表最后一个数据元素无后继。
if(L.elem[i]==cur_e){
next_e=L.elem[i+1] ;
cout<<next_e<<"的后继是:" << next_e <<endl;
return TRUE ;
}
/*else{
cout<<"表中未找到所要查找的数据元素。"<<endl;
return FALSE ;
}*/
//找不到在循环外说明。
}
cout<<"表中未找到所要查找的数据后继。"<<endl;
return FALSE ;
}
Status ListTraverse(SqList L){
if(!L.elem){
cout<<"顺序表不存在。"<<endl;
return FALSE ;
}
cout<<"依次将链表中的数据元素输出:"<<endl;
int i ;
for(i=0;i<L.length;i++){
cout<<" " << L.elem[i] ;
}
return TRUE ;
}
此外,顺序表还有一些不是经常用到的功能,比如对于两个现有的表La,Lb , 将存在于Lb中而不存在于La中的数据元素插入到表La中去,需要扩大线性表La 或者 将两个表合并为一个,其内的数据元素按照非递减的顺序排列。
void Union(SqList &La, SqList Lb); //将存在于Lb中而不存在于La中的数据元素插入到表La中
void MergeList(SqList La,SqList Lb,SqList &Lc); //将线性表La和表Lb合并到表Lc中
实现如下:
顺序表的合并:
void MergeList(SqList La,SqList Lb,SqList &Lc){
int i,j,k;
i=j=k=0;
ElemType pa , pb , pc ;
Lc.length = La.length+ Lb.length ;
Lc.elem = (ElemType*)malloc(Lc.listsize * sizeof(ElemType));
if(!Lc.elem){
cout<<"空间分配失败。"<<endl;
exit (OVERFLOW) ;
}
Lc.listsize = Lc.length ;
while((i<=La.length-1)&&(j<=Lb.length-1)){
pa = La.elem[i] ;
pb = Lb.elem[j] ;
if(pa<=pb){
Lc.elem[k]=pa;
i++;
k++;
}
else{
Lc.elem[k]=pb;
j++;
k++;
}
}
while(i<=La.length-1){
pa = La.elem[i] ;
Lc.elem[k]=pa;
i++;
k++;
}
while(j<=Lb.length-1){
pb = Lb.elem[j] ;
Lc.elem[k]=pb;
j++;
k++;
}
}
两个表之间数据元素的插入(这个功能能读懂,但代码部分涉及到了LcoateElem函数,判断元素间关系,我还没具体去看,不是很了解):
Status fun1(ElemType e,ElemType obj)
{
if(e==obj)
return TRUE;
return FALSE;
}
int LocateElem(SqList L,ElemType e,Status (*compare)(ElemType ,ElemType ))
{
int i=1;
ElemType *p=L.elem;
if(L.elem==NULL)
{
cout<<"顺序表不存在!"<<endl;
return -1;
}
while(i<=L.length && compare(*p,e)==FALSE)
{
i++;
p++;
}
if(i<=L.length)
return i;
return 0;
}
void Union(SqList &La, SqList Lb){
int La_len , Lb_len , i;
ElemType e ;
La_len = ListLength(La) ;
Lb_len = ListLength(Lb) ;
if(La_len+Lb_len > La.listsize){
ElemType *newbase ;
newbase = (ElemType *) realloc(La.elem,(La.listsize+LISTINCREMENT) * sizeof(ElemType));
La.elem = newbase ;
La.listsize += LISTINCREMENT ;
}
for(i=1;i<=Lb_len;i++){
GetElem(Lb,i,e);
if(!LocateElem(La,e,fun1))
ListInsert(La,++La_len,e);
}
}