ElemType.h
/***
*ElemType.h - ElemType的定义
*
****/
#ifndef ELEMTYPE_H
#define ELEMTYPE_H
typedef int ElemType; //定义数据类型
int compare(ElemType x, ElemType y); //声明判断函数
void visit(ElemType e); //声明打印函数
#endif /* ELEMTYPE_H */
DynaSeqList.h
/***
*
DynaSeqList.h - 动态顺序表的定义
*
****/
#if !defined(DYNASEQLIST_H)
#define DYNASEQLIST_H
#include "ElemType.h"
/*------------------------------------------------------------
顺序表结构的定义
------------------------------------------------------------*/
typedef struct List
{
ElemType *elem; // 存储空间的基址
int length; // 顺序表中结点元素的个数
int listsize; // 顺序表的存储空间大小
} SqList;
/*------------------------------------------------------------
// 顺序表的基本操作
------------------------------------------------------------*/
bool InitList(SqList *L); //线性表初始化
void DestroyList(SqList *L); //线性表销毁
bool ListEmpty(SqList L); //线性表判空
int ListLength(SqList L); //线性表长度
bool GetElem(SqList L, int i, ElemType *e); //获得下标 i 的数据元素
int LocateElem(SqList L, ElemType e, int (*fp)(ElemType, ElemType));//获得和元素e有关的元素
bool PriorElem(SqList L, ElemType cur_e, ElemType *pre_e); //获得数据元素的前驱
bool NextElem(SqList L, ElemType cur_e, ElemType *nxt_e); //获得数据元素的后继
void ListTraverse(SqList L, void (*fp)(ElemType)); //遍历线性表
void ClearList(SqList *L); //清空线性表
bool ListInsert(SqList* L, int i, ElemType e); //在 i 位置插入数据元素
void HeadInsert(SqList* L, ElemType e); //线性表的头部插入元素
void TailInsert(SqList* L, ElemType e); //线性表的尾部插入元素
bool ListDelete(SqList *L, int i, ElemType *e); //删除 i 位置的数据元素
void ListDeleteHead(SqList* L,ElemType* e); //删除线性表的头部元素
void ListDeleteTail(SqList* L,ElemType* e); //删除线性表的尾部元素
void unionList(SqList* La, SqList Lb); //求两个线性表的并集
#endif /* DYNASEQLIST_H */
DynaSeqList.cpp
/***
*DynaSeqList.cpp - 动态顺序表,即顺序表的动态数组实现
****/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <assert.h>
#include "DynaSeqList.h"
const int LIST_INIT_SIZE = 100; // 表初始分配的最大长度
const int LISTINCREMENT = 10; // 分配内存的增量
/*------------------------------------------------------------
操作目的: 初始化顺序表
初始条件: 无
操作结果: 构造一个空的线性表
函数参数:
SqList *L 待初始化的线性表
返回值:
bool 操作是否成功
------------------------------------------------------------*/
bool InitList(SqList *L)
{
L->elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
if (!L->elem)
return false;
else
{
L->length = 0;
L->listsize = LIST_INIT_SIZE;
return true;
}
}
/*------------------------------------------------------------
操作目的: 销毁顺序表
初始条件: 线性表L已存在
操作结果: 销毁线性表L
函数参数:
SqList *L 待销毁的线性表
返回值:
无
------------------------------------------------------------*/
void DestroyList(SqList *L)
{
if (L->elem)
free(L->elem);
L->elem = NULL;
}
/*------------------------------------------------------------
操作目的: 判断顺序表是否为空
初始条件: 线性表L已存在
操作结果: 若L为空表,则返回true,否则返回false
函数参数:
SqList L 待判断的线性表
返回值:
bool 是否为空
------------------------------------------------------------*/
bool ListEmpty(SqList L)
{
if (!L.length)
return true;
else
return false;
}
/*------------------------------------------------------------
操作目的: 得到顺序表的长度
初始条件: 线性表L已存在
操作结果: 返回L中数据元素的个数
函数参数:
SqList L 线性表L
返回值:
int 数据元素的个数
------------------------------------------------------------*/
int ListLength(SqList L)
{
return L.length;
}
/*------------------------------------------------------------
操作目的: 得到顺序表的第i个元素
初始条件: 线性表L已存在,1<=i<=ListLength(L)
操作结果: 用e返回L中第i个数据元素的值
函数参数:
SqList L 线性表L
int i 数据元素的位置
ElemType *e 第i个数据元素的值
返回值:
bool 操作是否成功
------------------------------------------------------------*/
bool GetElem(SqList L, int i, ElemType *e)
{
if (i < 1 || i > L.length)
return false;
else
*e = L.elem[i - 1];
return true;
}
/*------------------------------------------------------------
操作目的: 得到顺序表指定元素的位置
初始条件: 线性表L已存在
操作结果: 返回L中第一个与e满足关系compare()的数据元素的位序。
若这样的元素不存在则返回0。
函数参数:
SqList L 线性表L
ElemType e 数据元素e
int (*fp)() 用于比较相等的函数指针
返回值:
int 与e满足关系compare()的数据元素的位序
------------------------------------------------------------*/
int LocateElem(SqList L, ElemType e, int (*fp)(ElemType, ElemType))
{
for (int i = 0; i < L.length; i++)
{
if(!(*fp)(e,L.elem[i]))
return i + 1;
}
return 0;
}
/*------------------------------------------------------------
操作目的: 得到顺序表指定元素的前驱
初始条件: 线性表L已存在
操作结果: 若cur_e是L的数据元素,且不是第一个,则用pre_e返回
它的前驱,否则操作失败,pre_e无定义
函数参数:
SqList L 线性表L
ElemType cur_e 数据元素cur_e
ElemType *pre_e 前驱数据元素
返回值:
bool 操作是否成功
------------------------------------------------------------*/
bool PriorElem(SqList L, ElemType cur_e, ElemType *pre_e)
{
int i = LocateElem(L, cur_e, compare);
if (i!=0 && i!= 1)
{
*pre_e = L.elem[i - 2];
return true;
}
return false;
}
/*------------------------------------------------------------
操作目的: 得到顺序表指定元素的后继
初始条件: 线性表L已存在
操作结果: 若cur_e是L的数据元素,且不是最后一个,则用nxt_e返
回它的后继,否则操作失败,nxt_e无定义
函数参数:
SqList L 线性表L
ElemType cur_e 数据元素cur_e
ElemType *nxt_e 后继数据元素
返回值:
bool 操作是否成功
------------------------------------------------------------*/
bool NextElem(SqList L, ElemType cur_e, ElemType *nxt_e)
{
int i = LocateElem(L, cur_e, compare);
if (i!=0 && i != L.length)
{
*nxt_e = L.elem[i];
return true;
}
return false;
}
/*------------------------------------------------------------
操作目的: 遍历顺序表
初始条件: 线性表L已存在
操作结果: 依次对L的每个元素调用函数fp
函数参数:
SqList L 线性表L
void (*fp)() 访问每个数据元素的函数指针
返回值:
无
------------------------------------------------------------*/
void ListTraverse(SqList L, void (*fp)(ElemType))
{
for (int i = 0; i < L.length; i++)
(*fp)(L.elem[i]);
printf("\n");
}
/*------------------------------------------------------------
操作目的: 清空顺序表
初始条件: 线性表L已存在
操作结果: 将L置为空表
函数参数:
SqList *L 线性表L
返回值:
无
------------------------------------------------------------*/
void ClearList(SqList *L)
{
L->length = 0;
}
/*------------------------------------------------------------
操作目的: 在顺序表的指定位置插入结点,插入位置i表示在第i个
元素之前插入
初始条件: 线性表L已存在,1<=i<=ListLength(L) + 1
操作结果: 在L中第i个位置之前插入新的数据元素e,L的长度加1
函数参数:
SqList *L 线性表L
int i 插入位置
ElemType e 待插入的数据元素
返回值:
bool 操作是否成功
------------------------------------------------------------*/
bool ListInsert(SqList *L, int i, ElemType e)
{
ElemType* newbase = NULL;
if (i < 1 || i>L->length + 1)
return false;
if (L->length == L->listsize)
{
newbase = (ElemType*)realloc(L->elem, (LIST_INIT_SIZE + LISTINCREMENT) * sizeof(ElemType));
if (!newbase)
return false;
else
{
L->elem = newbase;
L->listsize += LISTINCREMENT;
}
}
for (int j = L->length; j >= i; j--)
L->elem[j] = L->elem[j - 1];
L->elem[i - 1] = e;
++L->length;
return true;
}
/*------------------------------------------------------------
操作目的: 在顺序表的指定位置插入结点,插入位置i表示在第i个
元素之前插入
初始条件: 线性表L已存在,1<=i<=ListLength(L) + 1
操作结果: 在L中第i个位置之前插入新的数据元素e,L的长度加1
函数参数:
SqList *L 线性表L
int i 插入位置
ElemType e 待插入的数据元素
返回值:
bool 操作是否成功
------------------------------------------------------------*/
void HeadInsert(SqList* L, ElemType e) //线性表的头插法
{
ListInsert(L, 1, e);
}
/*------------------------------------------------------------
操作目的: 在顺序表的指定位置插入结点,插入位置i表示在第i个
元素之前插入
初始条件: 线性表L已存在,1<=i<=ListLength(L) + 1
操作结果: 在L中第i个位置之前插入新的数据元素e,L的长度加1
函数参数:
SqList *L 线性表L
int i 插入位置
ElemType e 待插入的数据元素
返回值:
bool 操作是否成功
------------------------------------------------------------*/
void TailInsert(SqList* L, ElemType e) //线性表的尾插法
{
ListInsert(L, L->length + 1, e);
}
/*------------------------------------------------------------
操作目的: 删除顺序表的第i个结点
初始条件: 线性表L已存在且非空,1<=i<=ListLength(L)
操作结果: 删除L的第i个数据元素,并用e返回其值,L的长度减1
函数参数:
SqList *L 线性表L
int i 删除位置
ElemType *e 被删除的数据元素值
返回值:
bool 操作是否成功
------------------------------------------------------------*/
bool ListDelete(SqList* L, int i, ElemType* e)
{
if (i < 1 || i>L->length)
return false;
*e = L->elem[i -1];
for (int j = i - 1; j < L->length - 1; j++)
{
L->elem[j] = L->elem[j + 1];
}
--L->length;
return true;
}
void ListDeleteHead(SqList* L, ElemType* e) //线性表的头删法
{
ListDelete(L,1, e);
}
void ListDeleteTail(SqList* L, ElemType* e) //线性表的尾删法
{
ListDelete(L, L->length, e);
}
/*------------------------------------------------------------
操作目的: 求两个线性表的并集
初始条件: 两个线性表La 和 Lb 都已存在且非空,1<=i<=ListLength(La) 1<=i<=ListLength(Lb)
操作结果: 打印连接之后的线性表
函数参数:
SqList* La, SqList* Lb 求并集的两个线性表
返回值:
void 不需要返回值
------------------------------------------------------------*/
void unionList(SqList* La, SqList Lb)
{
int La_len = ListLength(*La);
int Lb_len = ListLength(Lb);
ElemType e = 0;
for (int i = 0; i < Lb_len; i++)
{
GetElem(Lb, i, &e); // 取 Lb 中第 i 个数据元素赋给 e
if (!LocateElem(*La, e, compare)) //如果e和线性表 La 的所有元素都不想等
ListInsert(La, La->length, e); //把 e 插入到La的尾部
else
continue;
}
}
ElemType.cpp
/***
*ElemType.cpp - ElemType的实现
*
****/
#include <stdio.h>
#include "ElemType.h"
int compare(ElemType x, ElemType y)
{
return(x-y);
}
void visit(ElemType e)
{
printf("%d\t", e);
}
Lab.cpp
#include <stdio.h>
#include "DynaSeqList.h"
int main()
{
SqList myList;
if (InitList(&myList))
printf("初始化成功\n");
else
printf("初始化失败\n");
//头插法
printf("头插法:\n");
for (int i = 0; i < 10; i++)
{
ListInsert(&myList, i, i * 10);
}
ListTraverse(myList, visit);
ElemType x = 0;
ElemType data = 0;
ListDelete(&myList, 2, &x);
printf("删除的是%d\n", x);
ListTraverse(myList, visit);
printf("在线性表头部插入数据元素值为666\n");
HeadInsert(&myList, 666);
ListTraverse(myList, visit);
printf("在线性表尾部插入数据元素值为258\n");
TailInsert(&myList, 258);
ListTraverse(myList, visit);
ListDeleteHead(&myList, &x);
printf("删除线性表的头部数据元素值为%d\n", x);
ListTraverse(myList, visit);
ListDeleteTail(&myList, &x);
printf("删除线性表的尾部数据元素值为%d\n", x);
ListTraverse(myList, visit);
x = 4;
data = 555;
if (ListInsert(&myList, x, data))
printf("成功在第%d的位置插入元素%d\n", x, data);
else
printf("在第%d的位置插入失败。\n", x);
ListTraverse(myList, visit);
x = 3;
if (ListDelete(&myList, x, &data))
printf("成功在第%d的位置删除元素%d\n", x, data);
else
printf("在第%d的位置删除失败。\n", x);
ListTraverse(myList, visit);
if (ListEmpty(myList))
printf("线性表为空\n");
else
printf("线性表非空\n");
printf("线性表长度为 %d\n", ListLength(myList));
x = 5;
if (GetElem(myList, x, &data))
{
printf("第%d位置的数据元素存在\n", x);
}
else
{
printf("%d位置的数据元素不存在\n", x);
}
printf("获得第%d位置的数据元素为%d\n", x, data);
x = 80;
printf("线性表中和%d相等的元素为%d\n", x, LocateElem(myList, x, compare));
x = 5;
if (GetElem(myList, x, &data))
{
printf("位置为%d的元素存在\n", x);
printf("位置为%d的元素下标为%d\n", x, data);
}
else
printf("位置为%d的元素不存在\n", x);
x = 70;
if (PriorElem(myList, x, &data))
printf("数据元素%d的前驱元素存在,前驱元素数值为%d\n", x, data);
else
printf("数据元素%d的前驱元素不存在", x);
x = 80;
if (NextElem(myList, x, &data))
printf("数据元素%d的后继元素存在,后继元素数值为%d\n", x, data);
else
printf("数据元素%d的后继元素不存在\n", x);
printf("清空线性表:\n");
ClearList(&myList);
if (!ListLength(myList))
printf("线性表清空成功\n");
else
printf("线性表清空失败\n");
printf("销毁线性表:\n");
DestroyList(&myList);
if (NULL ==myList.elem)
printf("线性表销毁成功\n");
else
printf("线性表销毁失败\n");
return 0;
}
测试结果
注意
上面我们所实现的线性表的基本操作数据类型为 int 类型,我们可以把ElemType设置为任何我们所需要的数据类型或者结构体类型,但是所有的操作都不需要搞定从而体现出来数据结构的灵活性,这是非常重要的一点需要读者去深刻体会。