先附整体代码,然后讲一下关键部分
#include <iostream>
using namespace std;
#define InitSize 100
typedef int ElemType;
typedef struct{
ElemType *data;
int MaxSize,length;
}SeqList;
void InitList(SeqList &L)//初始化
{
L.data=new ElemType[InitSize];
L.length=0;
L.MaxSize=INT_MAX;
}
int Length(SeqList &L)//表长
{
return L.length;
}
int LocateList (SeqList &L,int e)//按值输出
{
for(int i=0;i<L.length;i++)
if(L.data[i]==e) return i+1;
return 0;
}
int GetElem (SeqList L,int i)//按位输出
{
return L.data[i-1];
}
bool ListInsert(SeqList &L,int i,ElemType e) //插入
{
if(i<1||i>L.length+1)
return false;
if(L.length>=L.MaxSize)
return false;
for(int j=L.length;j>=i;j--)
L.data[j]=L.data[j-1];
L.data[i-1]=e;
L.length++;
return true;
}
bool ListDelete (SeqList &L,int i,ElemType e)//删除
{
if(i<1||i>L.length)
return false;
if(L.length<L.MaxSize)
return false;
for(int j=i;j<L.length;j++)
L.data[j-1]=L.data[j];
L.length--;
return true;
}
void PrintList(SeqList L)//输出
{
for(int i=0;i<L.length;i++)
cout<<L.data[i]<<endl;
}
bool Empty(SeqList L)//判空
{
if(L.length==0) return true;
return false;
}
void DestroyList(SeqList &L)//销毁操作
{
L.length=0;
L.MaxSize=NULL;
L.data=NULL;
delete L.data;
}
int main()
{
SeqList L;
InitList(L);
if(Empty(L)) cout<<"Empty"<<endl;
for(int i=1;i<200;i++)
{
ListInsert(L,i,i);
}
PrintList(L);
DestroyList(L);
PrintList(L);
if(Empty(L)) cout<<"Empty"<<endl;
return 0;
}
第一部分、声明
typedef struct{
ElemType *data;
int MaxSize,length;
}SeqList;
这个部分主要声明了一个线性表,包括三个部分,一个指针,一个上限,一个有效长度,比较容易理解。
第二部分、初始化
void InitList(SeqList &L)//初始化
{
L.data=new ElemType[InitSize];
L.length=0;
L.MaxSize=INT_MAX;
}
要求有效长度为0,因为线性表内部没有元素。
MaxSize自定义,尽量大一些。
new为分配动态内存,这样即使InitSize少于输入的长度,比如InitSize为100,但是输入199个数据到线性表中都不会溢出,如下所示:
for(int i=1;i<200;i++)
{
ListInsert(L,i,i);
}
第三部分、表长
int Length(SeqList &L)//表长
{
return L.length;
}
第四部分、按值查找
int LocateList (SeqList &L,int e)//按值输出
{
for(int i=0;i<L.length;i++)
if(L.data[i]==e) return i+1;
return 0;
}
遍历线性表,返回特定值的位序,注意不是数组的序号。
第五部分、按位查找
int GetElem (SeqList L,int i)//按位输出
{
return L.data[i-1];
}
直接输出就行。
第六部分、插入
bool ListInsert(SeqList &L,int i,ElemType e) //插入
{
if(i<1||i>L.length+1)
return false;
if(L.length>=L.MaxSize)
return false;
for(int j=L.length;j>=i;j--)
L.data[j]=L.data[j-1];
L.data[i-1]=e;
L.length++;
return true;
}
这里需要注意的地方很多,
第一点是合法性判断,因为位序从1开始且最后一位可以插入元素,所以是1到length+1。
第二点是长度判断,不允许表的有效长度超过内存上限
第三点是插入,循环部分是针对非尾端插入的情况,即将插入点右端的元素整体右移一个单位,这里要注意,i是位序不是数组序号,起点是有效线性表的的末端,注意这个有效是不包含空的长度,最后一位元素被放到了之前空的位置;大于等于i是因为从右端的第一个元素开始移动,使用位序作为数组序号时,便是指该元素的右端第一个元素。循环中的赋值操作很好理解。
第四点是插入,i-1还是位序和数组序号的区别。
最后有效长度增加要注意。
第七部分、删除
bool ListDelete (SeqList &L,int i,ElemType e)//删除
{
if(i<1||i>L.length)
return false;
if(L.length<L.MaxSize)
return false;
for(int j=i;j<L.length;j++)
L.data[j-1]=L.data[j];
L.length--;
return true;
}
如果插入理解了,删除的操作也差不多,这里不做赘述,需要注意循环起点和终点的差异即可,注意有效长度需要减少。
第八部分、输出
void PrintList(SeqList L)//输出
{
for(int i=0;i<L.length;i++)
cout<<L.data[i]<<endl;
}
这里直接遍历输出即可,当然也可以用重载“<<”算符的方法,这样输出看着比较简洁。
第九部分、判空
bool Empty(SeqList L)//判空
{
if(L.length==0) return true;
return false;
}
如果线性表有效长度为0,即表示表内没有元素了。
第十部分、销毁
void DestroyList(SeqList &L)//销毁操作
{
L.length=0;
delete L.data;
L.MaxSize=NULL;
L.data=NULL;
}
用glb单步调的时候可以发现声明后的结构体,其data指针是NULL,现在让它恢复到之前的状态即可,length和MaxSize也注意操作,可以再写一个析构函数判断结构体的内存释放,虽然delete代表了一种,但是可以加一些判断语句。
当然上述的函数也可以用友元或者成员函数写,这个看个人喜好。