前言
第一次写个人博客,这一切还要从一只蝙蝠说起…
在家闲着也是无聊,回顾一下上学期刚学完的数据结构,就当做是一个总结和查漏补缺,主要还是写给自己看,不过我把完整的头文件代码贴在最后,如果大家有需要可以直接使用。
1、什么是线性表?
线性表
是n个数据元素(结点)a1, a2, …an组成的有序
序列。其中数据元素的个数n定义为表的长度
,当n=0时成为空表,非空的线性表(n>0)记作:
其实经过一个学期数据结构学习,我发现掌握逻辑结构的定义往往是理解整个概念的重中之重,因此我觉得此处有必要对这个定义中的一些关键词作出解释。
有序
在线性表定义中的这个有序常常会让人感到十分迷惑,我们的直觉告诉我们,有序无非是递增或递减的排序,然而如果这样理解那么你就无法区分之后将要学习的查找表
和顺序表
到底有什么区别了。
因此,我们有必要明确,以上的线性表定义是逻辑结构
的定义,其中不会涉及存储内容的排序问题(这将适用于之后所有的逻辑结构定义)。此处的有序,指的是元素的前后关系
,让我们举个复杂点的例子来说明,以免被大小关系误导。
姓名 | 性别 | 年龄 |
---|---|---|
张三 | 男 | 20 |
李四 | 男 | 18 |
小红 | 女 | 19 |
可以看到,上面给出的是一个相对简单的学生信息表,我们同样可以将其看做一个线性表,那么它的数据元素即为每一行记录(每一列称为一个数据项
,数据元素由数据项组成)。
什么叫做有序呢?以李四所在行为例,他有唯一的直接前驱
张三,一个唯一的直接后继
小红;而对于整个表而言,只有一个开始结点
张三,他没有直接前驱,仅有一个直接后继,只有一个终端结点
小红,她没有直接后继,只有一个直接前驱。
表的长度
其实表的长度你不会理解错,这里说的就是表中元素的个数。但是这里提出来主要是为了引出如何从一个逻辑结构定义去转换为代码定义。一般我们去定义一个新的数据结构,所要做的无非就是一一对应
,换句话说,定义里只要有的,我们就要给出实现。下面我给出一个C语言的定义,让我们一起看看是否做到了一一对应。
typedef struct{ //顺序表定义
Elemtype *elem; //基地址
int length; //长度
int listsize; //容量
}SqList;
这里定义了一个顺序表,所谓顺序表就是用一组地址连续的存储单元依次存储线性表的数据元素。我们来看,线性表定义中,有三个重点:数据元素、有序序列、表的长度。显然做到了一一对应,并且我们还额外定义了容量
,这主要是为了确保我们给的数组不会越界。
线性表的顺序表示和实现
对于顺序表,其实上面已经给出了代码定义,也简单的对于顺序表的特点做出了解释,我们必须要明确,顺序表的定义属于存储结构
,因此会涉及到存储单元的描述。
假设线性表的每个元素占用n个存储单元,并且我们以第一个单元的存储地址作为数据元素的存储位置,那么线性表中第i个元素ai的存储位置为:
顺序表的定义理解起来并不困难,因为它本质上就是一个人为定义了一些规则的数组,那么具体有哪些规则呢?直接贴上头文件代码,顺序表相关实现很简单,因此除了函数功能以外没有写太多注释,从链表开始数据结构的难度大幅上升,注释也几乎会成为逐行注释。这里也呼吁各位一定要养成写注释的好习惯,方便自己,方便大家。
ps:github链接
#pragma once
#include<iostream>
#include<stdlib.h>
using namespace std;
const int LIST_INIT_SIZE = 100;
const int LISINCREMENT = 10;
typedef int Elemtype;
typedef struct{ //顺序表定义
Elemtype *elem; //基地址
int length; //长度
int listsize; //容量
}SqList;
void InitList(SqList &L) //初始化顺序表,开辟空间
{
L.elem = (Elemtype*)malloc(LIST_INIT_SIZE * sizeof(Elemtype));
if (!L.elem)
{
cerr << "OVERFLOW";
exit(1);
}
L.length= 0;
L.listsize = LIST_INIT_SIZE;
}
void DestroyList(SqList &L) //摧毁顺序表
{
if (L.elem)
{
cerr << "ERROR";
exit(1);
}
free(L.elem);
L.length = 0;
L.listsize = 0;
}
void ListInsert(SqList &L, int i, Elemtype e) //向顺序表第i个位置插入e
{
if (i<1 || i>L.length + 1) //判断插入位置是否有效, 注意从下标1开始保存
{
cerr << "ERROR";
exit(1);
}
if (L.length >= L.listsize) //判断顺序表是否已满
{
Elemtype *newbase = (Elemtype*)realloc(L.elem, (L.listsize + LISINCREMENT) * sizeof(Elemtype));
if (!newbase)
{
cerr << "ERROR";
exit(1);
}
L.elem = newbase;
L.listsize += LISINCREMENT;
}
Elemtype *q = &(L.elem[i]); //q指向插入位置
for (Elemtype *p = &(L.elem[L.length - 1]); p >= q; --p) //移位操作
{
*(p + 1) = *p;
}
*q = e;
++L.length;
}
Elemtype ListDelete(SqList &L, int i) //删除第i个元素,并返回值
{
if ((i < 1) || (i > L.length))
{
cerr << "ERROR";
exit(1);
}
Elemtype *p = &(L.elem[i]); //删除元素位置
Elemtype e = *p;
Elemtype *q = L.elem + L.length - 1; //表尾位置
for (++p; p <= q; ++p)
{
*(p - 1) = *p;
}
--L.length;
return e;
}
Elemtype GetElem(SqList &L, int i) //返回顺序表第i个元素
{
return L.elem[i];
}
bool compare(Elemtype a, Elemtype b) //判断元素是否相等,若相等则找到相同元素,返回false
{
if (a == b)
return false;
else
return true;
}
Elemtype LocateElem(SqList &L, Elemtype e) //在线性表中查找第一个与e相等的元素的位置
{
int i = 1;
Elemtype *p = L.elem;
while (i <= L.length && compare(*p++, e))
++i;
if (i <= L.length)
return i;
else
return 0;
}
SqList MergeList(SqList La, SqList Lb) //将两个顺序表按元素从小到大合并
{
SqList Lc;
Elemtype* pa,*pb;
pa = La.elem;
pb = Lb.elem;
Lc.listsize = Lc.length = La.length + Lb.length;
Elemtype *pc;
pc = Lc.elem = (Elemtype*)malloc(Lc.listsize * sizeof(Elemtype));
if (!Lc.elem)
{
cerr << "ERROR";
exit(1);
}
Elemtype *pa_last = La.elem + La.length - 1;
Elemtype *pb_last = Lb.elem + Lb.length - 1;
while (pa <= pa_last && pb <= pb_last)
{
if (*pa <= *pb)
{
*pc++ = *pa++;
}
else
{
*pc++ = *pb++;
}
}
while (pa <= pa_last)
{
*pc++ = *pa++;
}
while (pb <= pb_last)
{
*pc++ = *pb++;
}
return Lc;
}
SqList CombineList(SqList La, SqList Lb) //将Lb中元素插入到La尾部,保证不重复
{
SqList Lc;
Lc.listsize = La.length + Lb.length;
Elemtype* pc = Lc.elem = (Elemtype*)malloc(Lc.listsize * sizeof(Elemtype));
Lc.length = 0;
Elemtype *pa = La.elem;
Elemtype *pb = Lb.elem;
Elemtype *pa_last = La.elem + La.length - 1;
Elemtype *pb_last = Lb.elem + Lb.length - 1;
int i = 0;
for (i=1; pa < pa_last; pa++,i++)
{
ListInsert(Lc, i, *pa); //将La中元素插入到Lc
}
for (pb; pb < pb_last; pb++)
{
if (!LocateElem(La, *pb))
{
ListInsert(Lc,i++,*pb);
}
}
return Lc;
}
void PrintList(SqList L)
{
int i;
for (i = 1; i <= L.length; i++)
{
printf("%d ", GetElem(L, i));
}
printf("\n");
}
参考资料
1、中国大学MOOC——数据结构
2、《数据结构(C语言版)》严蔚敏编译