一、线性表概述
(一)线性表的定义
线性表是0个或n个数据元素的有限序列。表中元素存在一对一的线性关系,根据他们之间的关系可以构成一个线性序列,记作
(a1,a2,...,ai-1,ai,ai+1,...,an)
其中ai-1的排列位序先于ai,依次ai又先于ai+1,则我们称ai-1是ai的直接前驱,ai+1是ai的直接后继。对于其下标n(n≥0)定义为线性表的长度,当n=0时,则线性表被称为空表。
(二)线性表的主要操作
1)初始化函数:InitList(List&L)
执行条件:线性表L不存在
执行结果:建立一个空的线性表L
2)清空函数:ClearList(List&L)
执行条件:线性表存在且非空
执行结果:将线性表清理为空表
3)查找函数:LocateElem(List&L,int e)
执行条件:线性表非空
执行结果:在线性表中查找与给定元素e相等的元素,如果查找成功,返回该元素在表中的序号,否则,返回0表示失败
4)取值函数:GetElem(List L,int i,int *e)
执行条件:线性表非空,序号i在正确的范围内
执行结果:将线性表L中第i个元素值返回给e
5)插入函数:InsertList(List &L,int i,int e)
执行条件:序号i在正确的范围内
执行结果:在线性表L中第i个位置插入元素e,若插入成功则返回1,否则返回0表示失败
6)删除函数:ListDelete(List &L,int i,int *e)
执行条件:线性表非空,i在正确的范围内
执行结果:删除线性表中第i个元素,并返回被删除的元素给变量e
7)表长计算函数:ListLength(List L)
执行条件:线性表存在
执行结果:返回线性表L的元素个数
二、顺序表
线性表的存储方式有两种:顺序和链表,用顺序存储方式实现的线性表为顺序表,用一维数组作为其存储结。
(一)顺序表的定义
把线性表中的所有元素按照其逻辑顺序依次存储在一块连续的存储空间中,这块连续的空间则被称为顺序表,顺序表中每个元素的类型为ElemType,则每个元素所占的空间大小为sizeof(ElemType).
(二)顺序表的结构定义
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100 // 顺序表的最大容量
#define ElemType int //ElemType是指元素的类型,这里先用int代替
#define Status int //表示操作后的状态如OK等
#define ERROR 0 //表示操作有误
#define OK 1 //表示操作成功
typedef struct _SEQ_LIST_{
ElemType data[MAXSIZE];//大小为MAXSIZE的数组,用于存储数据
int length;//表示线性表当前的长度
}SqList;
不难发现,顺序存储的线性表具备一下特点:
存储空间的位置:数组data的位置即为线性表存储空间的位置
线性表的最大容量:数组长度MAXSIZE
线性表当前的长度:length
线性表各个元素地址的计算方式:Loc(ai)=Loc(ai)+(i-1)*(sizeof(ElemType))
(三)顺序存储的线性表具体操作的实现
void InitList(SqList& L)
{
L.length = 0; //直接初始化设置长度为0
}
Status ClearList(SqList& L)
{
L.length = 0;//清空原数组,长度变为0
return OK;
}
Status ListLength(SqList L)
{
return L.length;//直接返回数组长度
}
Status LocateElem(SqList L, int e)
{
int i;
for (i = 0;i < L.length;i++) {
if (L.data[i] == e)return i;//找到元素e,返回索引i
}
return ERROR;//未找到元素e,返回ERROR
}
Status GetElem(SqList L, int i, int* e)
{
if (i<1 || i>L.length)return ERROR;//判断所求元素索引是否在正确的范围内
*e = L.data[i - 1];
return *e;//返回所求元素
}
Status InsertList(SqList& L, int i, int e)
{
if (i<1 || i>L.length + 1)return ERROR;//判断所求元素索引是否在正确的范围内
if (L.length == MAXSIZE)return ERROR;//如果线性表已满,则返回ERROR表示错误
for (int j = L.length;j >= i;j--) {
L.data[j] = L.data[j - 1];
}
L.data[i - 1] = e;
return OK;
}
Status ListDelete(SqList& L, int i, int* e)
{
if (i<i || i>L.length)return ERROR;//判断i是否在正确的范围同时确保线性表中存在元素
for (int j = i - 1;j < L.length;j++) {
L.data[j] = L.data[j + 1];
}
L.length--;
return OK;
}
三、线性表链式存储的结构定义
线性表的链式存储结构:n个结点(ai的存储映像)链结成的一个链表。其中,每个结点存储数据元素信息的域称为数据域,存储直接后继位置的域为指针域。指针域中存储的信息称作指针或链。
(二)线性表链式存储结构代码描述
typedef struct NODE {
ElemType data;//结点的数据域
NODE* next;//存储当前结点的下一结点的地址
}Lnode, *LinkList;
通过其结构定义,我们不难发现,结点由存放该元素的数据域和存放后继结点地址的指针域组成。若pos为指向线性表中第i个元素的指针 ,则ai的数据域我们可以用pos->data来表示,其下一个元素的地址可以用p->next来表示,则p->next->data表示为ai+1这一结点的数据域。
(三)线性表链式存储结构具体操作的代码实现
//初始化链表
void InitList(LinkList L)
{
L->next = NULL;//将已存在的链表头结点的next指针置空
}
//计算链表长度
Status ListLength(const LinkList L)
{
int cnt = 0;
LinkList p = L->next;
while (p) {
cnt++;
p = p->next;
}
return cnt;
}
//清空链表
Status ClearList(LinkList L)
{
if (L->next == NULL)return ERROR;//若链表初始为空,则返回错误
LinkList p, q;
p = L->next;
q = p;
while (p) {
p = p->next;
free(q);
q = p;
}
free(p);
L->next = NULL;
return OK;//返回表示操作完成
}
//删除元素
Status ListDelete(LinkList L, int i, ElemType* e)
{
LinkList q,p=L;
int j = 1;
while (p || j < i) {
p = p->next;
j++;
}
if (!p || j > i)return ERROR;
q = p->next;
*e = q->data;
p->next = q->next;
free(q);
return OK;
}
//取值操作
Status GetElem(LinkList L, int i, int* e)
{
int j = 1;
LinkList p = L->next;
while (p && j < i) { //寻找第i-1个结点
p = p->next;
j++;
}
if (!p || j>i)return ERROR; //判断是否不存在或输入的i为负值
*e = p->data;
return OK;
}
//插入操作(1<=i<=ListLength(L))
Status ListInsert(LinkList L, int i, int e)
{
LinkList s,p = L->next;
int j = 1;
while (p && j < i-1) {
p = p->next;
j++;
}
if (!p || j > i)return ERROR; //结点i不存在
s = (LinkList)malloc(sizeof(Lnode));
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
(四) 单链表的整表创建(头插法与尾插法)
//头插法
void CreateListHead(LinkList L,int n)
{
LinkList p;
int i;
srand(time(0));//初始化随机数种子
L = (LinkList)malloc(sizeof(Lnode));
L->next = NULL;
for (i = 0;i < n;i++) {
p = (LinkList)malloc(sizeof(Lnode));
p->data = rand() % 100 + 1;
p->next = L->next;
L->next = p;
}
}
//尾插法
void CreateListTail(LinkList L, int n)
{
LinkList p,r; // r记录尾结点地址
int i;
srand(time(0));
L = (LinkList)malloc(sizeof(Lnode));
L->next = NULL;
r = L;
for (i = 0;i < n;i++) {
p = (LinkList)malloc(sizeof(Lnode));
p->data = rand() % 100 + 1;
r->next = p;
r = p;
}
r->next = NULL;表示链表链接结束
}