顺序表
注意:代码主要是用C++写的,对C语言有兼容性。
写在前面的话
相信很多人在看数据结构这本书的时候都云里雾里,书中的代码让人费解,而且代码还只是冰山一角,像我这种愚蠢的家伙就很是不解,照着书上的算法描述敲代码,结果就是一片红色警告。
这ElemType
是什么类型?C或者C++有这种类型吗?为什么会报错。
这Status
又是什么东西锕,怎么和书上写的一样都会报错锕…
这里,我们不说那些定义和特点,那些书上都有。
今天,我们只看代码该如何实现。
实现代码的前提
首先,书中并没有写明main
函数的具体实现,这里就由我自由发挥了。
然后,你需要了解一些关键知识。
比如:typedef
这个关键字就是为了给变量或什么东西起外号的,虽然它并不一定喜欢这个外号,也许这个外号让它的一世英名毁于一旦。但在个文件里,大家都这么叫它,都知道这个外号指的就是它。对此,它也无能为力。
语法:typedef 原名 外号;
示例:
typedef Book ElemType;
还有就是,原文中字符是直接用==
比较的:L.elem[i] == e
但我们这里的数据类型是Book
,外号叫ElemType
这种类型不能直接使用比较运算符,必须对运算符进行重载。
为了简化,我把图书结构中的一些字符型成员变量改成了字符串型。
最后,顺序表是从1开始的。顺序表的方法先是初始化方法,然后需要获取数据的方法,还需要能知道数据放在哪个位置的方法,还需要能增加数据的插入方法和删除数据的删除方法。
代码实现
看懂代码最关键的语句:
//给Book类型取外号为ElemType
typedef Book ElemType;
//给int类型取外号为Status
typedef int Status;
知道ElemType
和Status
都是外号后,理解起来就简单起来了。
#include<iostream>
#include<string>
using namespace std;
#define MAXSIZE 10 //宏定义,定义数组最大长度,对应顺序表的容量
//图书结构
typedef struct
{
string no; //图书ISBN编号
string name; //图书名称
float price; //图书价格
}Book;
//顺序表结构
typedef struct
{
Book* elem; //定义Book指针
int length; //顺序表的长度
int MaxSize;//此处为扩展知识,书上没有
}SqList;
//给Book类型取外号为ElemType
typedef Book ElemType;
//给int类型取外号为Status
typedef int Status;
/*
顺序表的初始化:
参数一:要初始化的顺序表
注意:成功:返回1;失败:退出程序,错误代码:3。
*/
Status InitList(SqList& L)//使用int类型的外号Status作为函数的返回值类型
{
L.MaxSize = MAXSIZE;
//L.elem = (Book*)malloc(MAXSIZE*sizeof(int)); //或者用malloc开辟空间
L.elem = new ElemType[MAXSIZE]; //使用Book类型的外号ElemType
//exit是退出整个进程,OVERFLOW的默认值为3,意思为栈溢出
if (!L.elem) exit(OVERFLOW);
L.length = 0;
return 1;
}
/*
顺序表的扩容(扩展知识,书上并没有这个)
扩容会大量移动数据,时间复杂度为O(n)
*/
void IncreaseSize(SqList &L,int len)
{
Book *p = L.elem;//将原来的地址给p
L.MaxSize += len;//容量加上扩容的数据
L.elem = new Book[L.MaxSize];//开辟新空间
//L.elem = (Book*)malloc(L.MaxSize*sizeof(int));
for (int i = 0; i < L.length; i++)//将原来的数据拷贝回来
{
/*
此处编译器警告:代码:C6385 说明:正在从"L.elem"读取无效数据。
尚不清楚是怎么回事,然而并不影响程序运行。
*/
L.elem[i] = p[i];
}
//delete(p);//这里应当释放的,但是这样编译器报错,程序崩溃。
//free(p);//如果用malloc开辟空间,就用free释放
}
/*
顺序表的取值:时间复杂度为O(1)
参数一:要取值的顺序表
参数二:要取值的位置
参数三:待保存的对象
注意:成功:返回1;失败:返回0。
*/
Status GetElem(SqList& L, int num, ElemType& e)//使用Book类型的外号ElemType作为传入参数e的类型,使用int类型的外号Status作为函数的返回值类型
{
if (num<1 || num>L.length)//先判断输入是否合法
{
return 0;
}
e = L.elem[num - 1]; //将获取的数值赋值给Book对象e
return 1;
}
/*
顺序表的查找:时间复杂度为O(n)
参数一:要查找的顺序表
参数二:要查找的数据
注意:成功:返回下标位置;失败:返回0。
*/
Status LocateElem(SqList L, ElemType e)//使用Book类型的外号ElemType作为传入参数e的类型,使用int类型的外号Status作为函数的返回值类型
{
for (int i = 0; i < L.length; i++)
{
//对比Book中的数据是否相等
if (L.elem[i].name == e.name && L.elem[i].no == e.no && L.elem[i].price == e.price)
{
return i + 1;//因为线性表是从1开始的
}
}
return 0;
}
/*
顺序表的插入:时间复杂度为O(n)
参数一:要插入的顺序表
参数二:要插入的位置
参数三:要插入的数据
注意:成功:返回1;失败:返回0。
*/
Status ListInsert(SqList& L, int num, ElemType e)//使用Book类型的外号ElemType作为传入参数e的类型,使用int类型的外号Status作为函数的返回值类型
{
if (L.length == MAXSIZE || num<1 || num >L.length + 1)//先判断输入是否合法
{
return 0;
}
for (int i = L.length - 1; i >= num - 1; i--)
{
L.elem[i + 1] = L.elem[i];
}
L.elem[num - 1] = e;
L.length++;//成功插入数据,length长度+1
return 1;
}
/*
顺序表的删除:时间复杂度为O(n)
参数一:要删除的顺序表
参数二:要删除的位置
注意:成功:返回1;失败:返回0。
*/
Status ListDelete(SqList& L, int num)//使用int类型的外号Status作为函数的返回值类型
{
if (num<1 || num >L.length || L.length == 0)//先判断输入是否合法
{
return 0;
}
//这里书上是i < L.length-1;是错误的
for (int i = num; i < L.length; i++)//删除数据就把num后的数据逐个前移,将其覆盖掉
{
L.elem[i-1] = L.elem[i];
}
L.length--;//成功删除数据,length长度-1
return 1;
}
int main()
{
SqList L;
Book book;
int temp = 0; //临时数据,用来判断执行是否成功
cout << "======================================" << endl;
cout << "1、初始化顺序表...";
temp = InitList(L);
if (!temp)
{
cout << "\t失败" << endl;
}
cout << "\t成功!" << endl;
book.no = "978-7-115-37950-4";
book.name = "数据结构(c语言版)(第2版)";
book.price = 35;
cout << "======================================" << endl;
cout << "2、往顺序表中插入数据...";
for (int i = 1; i <= 10; i++)
{
book.price = i;
temp = ListInsert(L, i, book);
}
if (!temp)
{
cout << "\t失败" << endl;
}
cout << "\t成功!" << endl;
cout << "======================================" << endl;
/*cout << "3、扩容...";
IncreaseSize(L, 5);
cout << "L.MaxSize :"<< L.MaxSize << endl;*/
cout << "3、获取图书的下标位置数据...";
temp = LocateElem(L, book);
if (!temp)
{
cout << "\t失败!" << endl;
}
cout << "\t成功!" << endl;
cout << "--------------------------------------" << endl;
cout << "下标位置为:" << temp << endl;
Book book1;
cout << "======================================" << endl;
cout << "4、在顺序表中取得数据...";
temp = GetElem(L, 1, book1);
if (!temp)
{
cout << "\t失败" << endl;
}
cout << "\t成功!" << endl;
cout << "--------------------------------------" << endl;
cout << "图书信息为:" << endl;
cout << "图书ISBN :" << book1.no
<< "\t图书名称:" << book1.name
<< "\t图书价格:" << book1.price << endl;
cout << "======================================" << endl;
cout << "5、删除顺序表中的数据...";
temp = ListDelete(L, 5);
if (!temp)
{
cout << "失败" << endl;
}
cout << "成功" << endl;
cout << "======================================" << endl;
for (int i = 1; i <= L.length; i++)
{
GetElem(L, i, book1);
cout << book1.price << endl;
}
system("pause");
return 0;
}
运行结果:
======================================
1、初始化顺序表... 成功!
======================================
2、往顺序表中插入数据... 成功!
======================================
3、获取图书的下标位置数据... 成功!
--------------------------------------
下标位置为:1
======================================
4、在顺序表中取得数据... 成功!
--------------------------------------
图书信息为:
图书ISBN :978-7-115-37950-4 图书名称:数据结构(c语言版)(第2版) 图书价格:35
======================================
5、删除顺序表中的数据...成功
======================================
请按任意键继续. . .
最后
当然,你也可以把程序改成switch
类型的循环结构,以输入输出的形式执行程序。
以上为个人实践总结,如有错误和疏漏的地方,欢迎大佬评论区指正和补充…
觉得写还不错的话,还请点赞、收藏、评论和分享,非常感谢~
参考文献:
- 《数据结构》C 语言版,严为敏 吴伟民编,清华大学出版社,2009.