这篇博客是关于动态线性表实现的详细代码,使用C语言实现每一个函数功能都有详细的功能,参数说明,条件和返回值,并且所有的功能函数都有完整的测试和截图
SqList.cpp(用于实现)
#include "SqList.h"
const int LIST_INIT_SIZE = 10; // 表初始分配的最大长度
/*------------------------------------------------------------
操作目的: 初始化顺序表
初始条件: 无
操作结果: 构造一个空的线性表
函数参数:
sqListPtr L 待初始化的线性表
返回值:
bool 操作是否成功
------------------------------------------------------------*/
bool InitList(sqListPtr L)
{
assert(L != NULL); //断言L不为空,如果L为空则所有操作都没有意义
if (L == NULL) //如果L为空
{
printf("%d\t %s error", __LINE__, __FILE__); //打印出错的文件和代码行数便于修改
exit(0);
}
L->elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType)); //动态申请10个空间
if ( NULL == L->elem )
{
printf("apply fail\n");
return false;
}
else
{
L->length = 0;
L->listsize = LIST_INIT_SIZE;
return true;
}
}
/*------------------------------------------------------------
操作目的: 销毁顺序表
初始条件: 线性表L已存在
操作结果: 销毁线性表L
函数参数:
sqListPtr L 待销毁的线性表
返回值:
无
------------------------------------------------------------*/
void DestroyList(sqListPtr L)
{
assert(L != NULL); //断言L不为空,如果L为空则所有操作都没有意义
if (L == NULL) //如果L为空
{
printf("%d\t %s error", __LINE__, __FILE__); //打印出错的文件和代码行数便于修改
exit(0);
}
free(L->elem);
L->elem = NULL;
}
/*------------------------------------------------------------
操作目的: 判断顺序表是否为空
初始条件: 线性表L已存在
操作结果: 若L为空表,则返回true,否则返回false
函数参数:
sqListPtr L 待判断的线性表
返回值:
bool 是否为空
------------------------------------------------------------*/
bool ListEmpty(sqListPtr L)
{
assert(L != NULL);
if (L == NULL)
{
printf("%d\t %s error", __LINE__, __FILE__);
exit(0);
}
if (0 == L->length )
return true;
else
return false;
}
/*------------------------------------------------------------
操作目的: 得到顺序表的长度
初始条件: 线性表L已存在
操作结果: 返回L中数据元素的个数
函数参数:
sqListPtr L 线性表L
返回值:
int 数据元素的个数
------------------------------------------------------------*/
int ListLength(sqListPtr L)
{
assert(L != NULL);
if (L == NULL)
{
printf("%d\t %s error", __LINE__, __FILE__);
exit(0);
}
return L->length;
}
/*------------------------------------------------------------
操作目的: 返回顺序表的第i个元素
初始条件: 线性表L已存在,1<=i<=ListLength(L)
操作结果: 用e返回L中第i个数据元素的值
函数参数:
sqListPtr L线性表L
int i 数据元素的位置
返回值:
顺序表的第i个元素
------------------------------------------------------------*/
int GetElem(sqListPtr L, int i)
{
assert(L != NULL); //断言L不为空,如果L为空则所有操作都没有意义
if (L == NULL) //如果L为空
{
printf("%d\t %s error", __LINE__, __FILE__); //打印出错的文件和代码行数便于修改
exit(0);
}
if (i < 1 || i > L->length)
{
printf("pos error\n");
exit(0);
}
return L->elem[i - 1];
}
/*------------------------------------------------------------
操作目的: 得到顺序表指定元素的前驱
初始条件: 线性表L已存在
操作结果: 返回前驱的值
函数参数:
SqList L 线性表L
当前位置i
返回值:
int 返回前驱元素的值
------------------------------------------------------------*/
int PriorElem(sqListPtr L,int i)
{
assert(L != NULL); //断言L不为空,如果L为空则所有操作都没有意义
if (L == NULL) //如果L为空
{
printf("%d\t %s error", __LINE__, __FILE__); //打印出错的文件和代码行数便于修改
exit(0);
}
if (0 != i && 1 != i)
return L->elem[i - 2];
return 0;
}
/*------------------------------------------------------------
操作目的: 得到顺序表指定元素的后继
初始条件: 线性表L已存在
操作结果: 返回i位置的后继值
函数参数:
SqList L 线性表L
当前操作的顺序表位置i
返回值:
int 返回后继元素的值
------------------------------------------------------------*/
int NextElem(sqListPtr L, int i)
{
assert(L != NULL); //断言L不为空,如果L为空则所有操作都没有意义
if (L == NULL) //如果L为空
{
printf("%d\t %s error", __LINE__, __FILE__); //打印出错的文件和代码行数便于修改
exit(0);
}
if (0 != i && L->length != i)
return L->elem[i];
return 0;
}
/*------------------------------------------------------------
操作目的: 遍历顺序表
初始条件: 线性表L已存在
操作结果: 打印顺序表中的每一个值
函数参数:
SqList L 线性表L
返回值:
无
------------------------------------------------------------*/
void ListTraverse(sqListPtr L)
{
for (int i = 0; i <= L->length -1 ; i++)
printf("%d\t", L->elem[i]);
printf("\n");
}
/*------------------------------------------------------------
操作目的: 清空顺序表
初始条件: 线性表L已存在
操作结果: 将L置为空表
函数参数:
SqList *L 线性表L
返回值:
无
------------------------------------------------------------*/
void ClearList(sqListPtr L)
{
assert(L != NULL); //断言L不为空,如果L为空则所有操作都没有意义
if (L == NULL) //如果L为空
{
printf("%d\t %s error", __LINE__, __FILE__); //打印出错的文件和代码行数便于修改
exit(0);
}
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(sqListPtr L, int i, ElemType e)
{
assert(L != NULL); //断言L不为空,如果L为空则所有操作都没有意义
if (L == NULL) //如果L为空
{
printf("%d\t %s error", __LINE__, __FILE__); //打印出错的文件和代码行数便于修改
exit(0);
}
if ((i < 1) || (i > L->length + 1))
{
printf("pos error\n");
return false;
}
//1.判断线性表是否为满
if (L->length == L->listsize)
{
//2.如果满了就扩容然后插入数据
ElemType* newbase = (ElemType*)realloc(L->elem, (LIST_INIT_SIZE) * 2 * sizeof(ElemType));
if (NULL == newbase)
{
printf("expension fail\n");
return false;
}
L->elem = newbase;
L->listsize *= 2;
for (int j = L->length; j >= i ; j--)
{
L->elem[j] = L->elem[j - 1];
}
L->elem[i - 1] = e;
++L->length;
return true;
}
else
{
//3.如果没有满则直接插入数据
for (int j = L->length; j >= i; j--)
{
L->elem[j] = L->elem[j - 1];
}
L->elem[i - 1] = e;
++L->length;
return true;
}
return false;
}
/*------------------------------------------------------------
操作目的: 删除顺序表的第i个结点
初始条件: 线性表L已存在且非空,1<=i<=ListLength(L)
操作结果: 删除L的第i个数据元素,并用e返回其值,L的长度减1
函数参数:
SqList *L 线性表L
int i 删除位置
ElemType *e 被删除的数据元素值
返回值:
bool 操作是否成功
------------------------------------------------------------*/
bool ListDelete(sqListPtr L, int i)
{
assert(L != NULL); //断言L不为空,如果L为空则所有操作都没有意义
if (L == NULL) //如果L为空
{
printf("%d\t %s error", __LINE__, __FILE__); //打印出错的文件和代码行数便于修改
exit(0);
}
if (i < 1 || i > L->length)
{
printf("pos error\n");
return false;
}
for (int j = i - 1; j < L->length-1; j++)
{
L->elem[j] = L->elem[j + 1];
}
--L->length;
return true;
}
/*------------------------------------------------------------
操作目的: 在顺序表表的头部插入元素
初始条件: 线性表已经存在
操作结果: 在线性表的头部插入一个元素并且把线性表长度+1
函数参数:
SqList *L 线性表L
所需要插入的数据
返回值:
不需要返回值 间接调用ListInsert函数
------------------------------------------------------------*/
void ListInsertHead(sqListPtr L, ElemType e)
{
ListInsert(L,1, e);
}
/*------------------------------------------------------------
操作目的: 在顺序表表的尾部插入元素
初始条件: 线性表已经存在
操作结果: 在线性表的尾部插入一个元素并且把线性表长度+1
函数参数:
SqList *L 线性表L
所需要插入的数据
返回值:
不需要返回值 间接调用ListInsert函数
------------------------------------------------------------*/
void ListInsertTail(sqListPtr L, ElemType e)
{
ListInsert(L, L->length + 1 , e);
}
/*------------------------------------------------------------
操作目的: 在顺序表表的头部删除元素
初始条件: 线性表已经存在
操作结果: 在线性表的头部删除一个元素并且把线性表长度-1
函数参数:
SqList *L 线性表L
返回值:
不需要返回值 间接调用ListDelete函数
------------------------------------------------------------*/
void ListDeleteHead(sqListPtr L)
{
ListDelete(L, 1);
}
/*------------------------------------------------------------
操作目的: 在顺序表表的尾部删除元素
初始条件: 线性表已经存在
操作结果: 在线性表的尾部删除一个元素并且把线性表长度-1
函数参数:
SqList *L 线性表L
返回值:
不需要返回值 间接调用ListDelete函数
------------------------------------------------------------*/
void ListDeleteTail(sqListPtr L)
{
ListDelete(L, L->length);
}
int compare(ElemType x, ElemType y)
{
return(x - y);
}
main.cpp(用于测试)
#include "SqList.h"
int main()
{
SqList list;
if (InitList(&list))
printf("初始化成功\n");
else
printf("初始化失败\n");
for (int i = 1; i <= 10; i++)
{
if (ListInsert(&list, i, i * 10))
printf("第%d位置元素插入成功\n",i);
else
printf("第%d位置元素插入失败\n", i);
}
ListTraverse(&list);
int Deleteops = 3;
if (ListDelete(&list, Deleteops))
printf("第%d位置元素删除成功\n", Deleteops);
ListTraverse(&list);
Deleteops = 5;
if (ListDelete(&list, Deleteops))
printf("第%d位置元素删除成功\n", Deleteops);
ListTraverse(&list);
ClearList(&list);
printf("清空线性表的结果为:");
ListTraverse(&list);
for (int i = 1; i <= 10; i++)
{
if (ListInsert(&list, i, i * 11))
printf("第%d位置元素插入成功\n", i);
else
printf("第%d位置元素插入失败\n", i);
}
ListTraverse(&list);
DestroyList(&list);
printf("销毁线性表的结果为:\n");
if (InitList(&list))
printf("初始化成功\n");
else
printf("初始化失败\n");
ListTraverse(&list);
for (int i = 1; i <= 10; i++)
{
if (ListInsert(&list, i, i * 22))
printf("第%d位置元素插入成功\n", i);
else
printf("第%d位置元素插入失败\n", i);
}
ListTraverse(&list);
int pos;
pos = 5;
printf("获得线性表的第%d个元素为:%d\n",pos,GetElem(&list, pos));
if (ListEmpty(&list))
printf("线性表为空\n");
else
printf("线性表不为空\n");
ListInsertHead(&list, 99);
printf("在线性表头部插入元素数据为 :99\n");
ListTraverse(&list);
ListInsertTail(&list, 999);
printf("在线性表尾部插入元素数据为 :999\n");
ListTraverse(&list);
ListDeleteHead(&list);
printf("删除顺序表头部元素结果为:\n");
ListTraverse(&list);
ListDeleteTail(&list);
printf("删除顺序表尾部元素结果为:\n");
ListTraverse(&list);
printf("当前线性表长度为:%d\n", ListLength(&list));
pos = 5;
printf("第%d位置的前驱元素为:%d\n", pos, PriorElem(&list, pos));
printf("第%d位置的后继元素为:%d\n", pos, NextElem(&list, pos));
return 0;
}
SqList.h(用于实现函数原型和数据类信)
/****
*
*动态顺序表的定义
*
****/
#pragma once //防止头文件重复包含
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <assert.h>
#include <stdio.h>
typedef int ElemType;
typedef struct List
{
ElemType* elem; //存储空间的基址
int length; //顺序表中已经存储的元素的个数
int listsize; //顺序表的存储空间大小
}SqList,*sqListPtr;
/*------------------------------------------------------------------------------------
//顺序表的基本操作
-------------------------------------------------------------------------------------*/
bool InitList(sqListPtr L); //初始化顺序表
void DestroyList(sqListPtr L); //销毁顺序表
bool ListEmpty(sqListPtr L); //判断顺序表是否为空
int ListLength(sqListPtr L); //得到顺序表的长度
int GetElem(sqListPtr L, int i); //得到顺序表的第i个元素
int PriorElem(sqListPtr L, int i); //得到顺序表指定元素的前驱
int NextElem(sqListPtr L, int i); //得到顺序表指定元素的后继
void ListTraverse(sqListPtr L); //遍历顺序表
void ClearList(sqListPtr L); //清空顺序表
bool ListInsert(sqListPtr L, int i, ElemType e); //在顺序表的指定位置插入结点,插入位置i表示在第i个元素之前插入
void ListInsertHead(sqListPtr L, ElemType e); //在顺序表的起始位置插入元素
void ListInsertTail(sqListPtr L,ElemType e); //在线性表的末尾位置插入元素
bool ListDelete(sqListPtr L, int i);// 删除顺序表的第i个结点
void ListDeleteHead(sqListPtr L ); //删除顺序表的起始元素
void ListDeleteTail(sqListPtr L ); //删除顺序表的末尾元素
int compare(ElemType x, ElemType y);
函数功能测试结果
小结
所有的函数功能实现已经大部分代码都有注释说明读者可以自行测试,在理解插入和删除元素的时候,注意数组下标的使用,最后希望如果是刚接触即使看懂了代码的功能自己也最好写一遍,有时候很多问题只有在写的时候才会发现。