在这里我们将介绍线性表的顺序存储结构–顺序表。这里我们介绍两种类型的顺序表,一种是静态的顺序表,另一种是动态增长的顺序表;并使用C和C++两种语言进行描述。这里给出C语言实现的具体的代码和说明,而C++的实现只是简单贴代码,不再详细说明。
一、相关概念
1.顺序表的概念
线性表的顺序存储结构称为顺序表(sequential list).
2.特点
(1)顺序表是用一段地址连续的存储单元一次存储线性表的数据元素;
(2)相邻元素不仅逻辑上相邻,而且在物理内存上也是相邻的;
(3)顺序表的元素可以随机存取(访问)
(4)插入和删除比较麻烦,需要大量移动元素
二、静态顺序表
1.结构体定义(C语言描述)
顺序表和数组本质上一样的,只不过比数组多了一个记录有效元素个数的变量,其他特点基本都一样,比如说随机访问等。
#define SIZE 10 //静态顺序表最大的元素个数上限
typedef struct Seqlist
{
int iElem_a[SIZE]; //顺序表总空间
int iLength_st;//表中有效元素个数
}Seqlist;
2.顺序表操作
我们将顺序表操作的函数的声明写在Seqlist.h文件中:
#ifndef SEQLIST_H_ //防止头文件被重复包含
#define SEQLIST_H_
#define SIZE 10
typedef struct Sqlist
{
int iElem_a[SIZE];
int iLength_st;
}Sqlist;
void InitSeqlist(Sqlist *pList); //顺序表初始化
bool Insert(Sqlist *pList, int iPos, int iVal);//插入
bool DeleteByPos(Sqlist *pList, int iPos);//删除
void Destroy(Sqlist *pList);//销毁顺序表,在静态顺序表中没实质性作用
void Clear(Sqlist *pList);//清空顺序表
bool IsEmpty(Sqlist *pList);//顺序表为空返回true
bool IsFull(Sqlist *pList);//顺序表满返回true
int GetLength(Sqlist *pList);//获取顺序表有效元素个数
bool GetValByPos(Sqlist *pList, int iPos, int *iRetVal);//获取指定位置元素
void PrintSqlist(Sqlist *pList);//输出顺序表
#endif
下面在Seqlist.c文件中给出顺序表操作的具体实现:
#include <stdio.h>
#include <stdlib.h>
#include "Seqlist.h"
int main(void)
{
Sqlist list;
InitSeqlist(&list);
for (int i = 0; i < 12; ++i)
{
Insert(&list, 0, i);
}
PrintSqlist(&list);
Insert(&list, 10, 10);
PrintSqlist(&list);
/*for (int i = 0; i < 12; ++i)
{
DeleteByPos(&list, 0);
PrintSqlist(&list);
}
PrintSqlist(&list);*/
for (int i = 0; i < 12; ++i)
{
int iRt;
GetValByPos(&list, i, &iRt);
printf("%5d\n", iRt);
}
printf("\n");
return 0;
}
//初始化顺序表,注意异常情况检查
void InitSeqlist(Sqlist *pList)
{
if (NULL == pList) //确保链表存在
{
printf("The Seqlist isn't exist!!!\n");
return;
}
pList->iLength_st = 0;
}
//插入元素,先判断是否顺序表已满,然后再判断插入位置是否正确,移动元素插入
bool Insert(Sqlist *pList, int iPos, int iVal)
{
//顺序表存在而且没有满
if (pList == NULL)
{
printf("The Sqlist isn't exist!!!\n");
return false;
}
if (IsFull(pList))
{
printf("The Sqlist is full!\n");
return false;
}
//插入位置是否合法
if (iPos > pList->iLength_st || iPos < 0)
{
printf("The Insert positon is valid.\n");
return false;
}
//移动元素
for (int iIndex = pList->iLength_st - 1; iIndex >= iPos; --iIndex)
{
pList->iElem_a[iIndex + 1] = pList->iElem_a[iIndex];
}
//放入
pList->iElem_a[iPos] = iVal;
pList->iLength_st += 1;
return true;
}
//删除指定位置的元素,找到删除的元素的位置后,直接移动元素进行覆盖,记得改变顺序表有效元素的个数
bool DeleteByPos(Sqlist *pList, int iPos)
{
if (NULL == pList)
{
printf("The seqlist isn't exist!!!\n");
return false;
}
if (IsEmpty(pList))
{
//printf("The seqlist is empty!!!\n");
return false;
}
if (iPos < 0 || iPos > pList->iLength_st - 1)
{
printf("The insert position is valid!!!\n");
return false;
}
for (int iIndex = iPos; iIndex < pList->iLength_st - 1; ++iIndex)
{
pList->iElem_a[iIndex] = pList->iElem_a[iIndex + 1];
}
--pList->iLength_st;
return true;
}
//销毁顺序表,因为这里是静态顺序表,所以这个函数没有实质性的作用
void Destroy(Sqlist *pList)
{
Clear(pList);
}
//清空顺序表,直接将记录顺序表有效元素个数的变量置为0
void Clear(Sqlist *pList)
{
if (NULL == pList)
{
printf("The seqlist isn't exist\n");
return;
}
pList->iLength_st = 0;
}
//判断顺序表是否为空
bool IsEmpty(Sqlist *pList)
{
if (NULL == pList)
{
printf("The Seqlist isn't exist!!!\n");
return false;
}
return 0 == pList->iLength_st;
}
//判断顺序表是否已满
bool IsFull(Sqlist *pList)
{
if (NULL == pList)
{
printf("The Seqlist isn't exist!!!\n");
return false;
}
return SIZE == pList->iLength_st;
}
//获取顺序表有效元素的个数
int GetLength(Sqlist *pList)
{
if (NULL == pList)
{
printf("The seqlist isn't exist.\n");
return -1;
}
return pList->iLength_st;
}
//获取顺序表中iPos位置元素的值
bool GetValByPos(Sqlist *pList, int iPos, int *iRetVal)
{
if (NULL == pList)
{
printf("The seqlist isn't exist.\n");
return false;
}
if (iPos < 0 || iPos >= pList->iLength_st)
{
printf("The position is valid\n");
return false;
}
*iRetVal = pList->iElem_a[iPos];
return true;
}
//打印顺序表中的元素
void PrintSqlist(Sqlist *pList)
{
if (NULL == pList || pList->iLength_st == 0)
{
return;
}
for (int iCount = 0; iCount < pList->iLength_st; ++iCount)
{
printf("%5d", pList->iElem_a[iCount]);
}
printf("\n");
}
三、动态顺序表
动态顺序表和静态顺序表的区别在于动态顺序表可以动态进行增长,而静态顺序表的最大容量是在程序运行前已经写好的,无法改变。
1.结构体定义(C语言描述)
#define INIT_SIZE 10 //初始化顺序表大小
#define INC_SIZE 10 //顺序表的分配增量
typedef struct DSqlist
{
int *iElem_st; //存储空间基址
int iLength_st; //当前长度
int iSize_st; //当前分配的存储容量
}DSqlist;
2.动态顺序表操作
动态增长的顺序表和静态顺序表的操作大部分相同,主要不同在于两个地方。一个是当顺序表满时,动态顺序表可以再增长从而插入元素,而静态顺序表则无法再插入元素;二是在销毁顺序表时两者不一样。
我们将顺序表操作的函数的声明写在DynamicSeqlist.h文件中:
#ifndef DYNAMICSEQLIST_H_
#define DYNAMICSEQLIST_H_
#define INIT_SIZE 10 //初始化顺序表大小
#define INC_SIZE 10 //顺序表的分配增量
typedef struct DSqlist
{
int *iElem_st; //存储空间基址
int iLength_st; //当前长度
int iSize_st; //当前分配的存储容量
}DSqlist;
bool IsExist(DSqlist *pList); //判断顺序表是否存在
void InitDSeqlist(DSqlist *pList); //初始化
bool Insert(DSqlist *pList, int iPos, int iVal);//插入
bool DeleteByPos(DSqlist *pList, int iPos); //删除
void Destroy(DSqlist *pList); //销毁
void Clear(DSqlist *pList); //清空
bool IsEmpty(DSqlist *pList); //判断是否为空
bool IsFull(DSqlist *pList); //判断是否为满
int GetLength(DSqlist *pList); //获取有效元素个数
bool GetValByPos(DSqlist *pList, int iPos, int *iRetVal); //获取指定位置元素的值
void PrintSqlist(DSqlist *pList); //打印元素
bool Resize(DSqlist *pList); //重新分配内存空间
#endif
下面在DynamicSeqlist.c文件中给出在以上操作的具体C语言代码实现:
#include"DynamicSeqlist.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
DSqlist list;
InitDSeqlist(&list);
for (int i = 0; i < 15; ++i)
{
Insert(&list, 0, i);
}
PrintSqlist(&list);
printf("%5d\n", list.iSize_st);
for (int i = 0; i < 15; ++i)
{
DeleteByPos(&list, 0);
PrintSqlist(&list);
}
PrintSqlist(&list);
return 0;
}
bool IsExist(DSqlist *pList)
{
return pList != NULL;
}
void InitDSeqlist(DSqlist *pList)
{
if (!IsExist(pList))
{
printf("The dynamic seqlist isn't exist.\n");
return;
}
pList->iElem_st = (int*)malloc(sizeof(int) * INIT_SIZE);
if (NULL == pList->iElem_st)
{
printf("Alloc the memory is failed.\n");
return;
}
pList->iSize_st = INIT_SIZE;
pList->iLength_st = 0;
}
bool Insert(DSqlist *pList, int iPos, int iVal)
{
if (!IsExist(pList))
{
printf("The dynamic seqlist isn't exist.\n");
return false;
}
if (IsFull(pList))
{
Resize(pList);
}
if (iPos < 0 || iPos > pList->iLength_st)
{
printf("The insert position is valid.\n");
return false;
}
for (int iIndex = pList->iLength_st - 1; iIndex >= iPos; --iIndex)
{
pList->iElem_st[iIndex + 1] = pList->iElem_st[iIndex];
}
pList->iElem_st[iPos] = iVal;
pList->iLength_st++;
return true;
}
bool DeleteByPos(DSqlist *pList, int iPos)
{
if (!IsExist(pList))
{
printf("The dynamic seqlist isn't exist.\n");
return false;
}
if (IsEmpty(pList))
{
printf("The seqlist is empty.\n");
return false;
}
if (iPos < 0 || iPos >= pList->iLength_st)
{
printf("The delete position is valid.\n");
return false;
}
for (int iIndex = iPos; iIndex < pList->iLength_st - 1; ++iIndex)
{
pList->iElem_st[iIndex] = pList->iElem_st[iIndex + 1];
}
pList->iLength_st--;
return true;
}
void Destroy(DSqlist *pList)
{
if (!IsExist(pList))
{
printf("The dynamic seqlist isn't exist.\n");
return;
}
free(pList->iElem_st);
pList->iLength_st = 0;
pList->iSize_st = 0;
pList->iElem_st = NULL;
}
void Clear(DSqlist *pList)
{
if (!IsExist(pList))
{
printf("The dynamic seqlist isn't exist.\n");
return;
}
pList->iLength_st = 0;
}
bool IsEmpty(DSqlist *pList)
{
if (!IsExist(pList))
{
printf("The dynamic seqlist isn't exist.\n");
return false;
}
return (pList->iLength_st == 0);
}
bool IsFull(DSqlist *pList)
{
if (!IsExist(pList))
{
printf("The dynamic seqlist isn't exist.\n");
return false;
}
return (pList->iLength_st == pList->iSize_st);
}
int GetLength(DSqlist *pList)
{
if (!IsExist(pList))
{
printf("The dynamic seqlist isn't exist.\n");
return -1;
}
return pList->iLength_st;
}
bool GetValByPos(DSqlist *pList, int iPos, int *iRetVal)
{
if (!IsExist(pList))
{
printf("The dynamic seqlist isn't exist.\n");
return false;
}
if (iPos < 0 || iPos >= pList->iLength_st)
{
printf("The posiont is valid.\n");
return false;
}
*iRetVal = pList->iElem_st[iPos];
return true;
}
void PrintSqlist(DSqlist *pList)
{
if (!IsExist(pList))
{
printf("The dynamic seqlist isn't exist.\n");
return;
}
for (int iIndex = 0; iIndex < pList->iLength_st; ++iIndex)
{
printf("%5d", pList->iElem_st[iIndex]);
}
printf("\n");
}
bool Resize(DSqlist *pList)
{
if (!IsExist(pList))
{
printf("The dynamic seqlist isn't exist.\n");
return false;
}
int *pTemp = pList->iElem_st;
pList->iElem_st = (int*)malloc(sizeof(int)*(pList->iSize_st + INC_SIZE));
if (NULL != pList->iElem_st)
{
memcpy(pList->iElem_st, pTemp, sizeof(int) * pList->iSize_st);
pList->iSize_st += INC_SIZE;
free(pTemp);
pTemp = NULL;
return true;
}
else
{
return false;
}
}
下面直接给出使用C++实现顺序表的代码:
//CppSeqlist.h头文件
#pragma once
const int SIZE = 10;
class CSeqList
{
public:
CSeqList();
~CSeqList();
int Length();
bool Get(int i, int &iRtVal);
int Locate(int x);
void Insert(int i, int x);
void Detele(int i);
void PrintList();
private:
int _iData_a[SIZE]; //存放数据元素的数组
int _iLength; //线性表的长度
};
//CppSeqlist.cpp
#include "CppSeqlist.h"
#include <iostream>
using namespace std;
CSeqList::CSeqList()
{
_iLength = 0;
}
CSeqList::~CSeqList()
{
}
int CSeqList::Length()
{
return _iLength;
}
bool CSeqList::Get(int i, int &iRtVal)
{
if (i < 0 || i > _iLength - 1)
{
cout << "the position is valid.\n" << endl;
return false;
}
iRtVal = _iData_a[i];
return true;
}
void CSeqList::Insert(int i, int x)
{
if (_iLength == SIZE)
{
cout << "The seqlist is full." << endl;
return;
}
if (i < 0 || i > _iLength)
{
cout << "the position is valid." << endl;
return;
}
for (int iIndex = _iLength - 1; iIndex >= i; --iIndex)
{
_iData_a[iIndex + 1] = _iData_a[iIndex];
}
_iData_a[i] = x;
++_iLength;
}
void CSeqList::Detele(int i)
{
if (i < 0 || i > _iLength - 1)
{
cout << "The position is valid." << endl;
return;
}
for (int iIndex = i; iIndex < _iLength - 1; ++iIndex)
{
_iData_a[iIndex] = _iData_a[iIndex + 1];
}
--_iLength;
}
void CSeqList::PrintList()
{
for (int iIndex = 0; iIndex < _iLength; ++iIndex)
{
cout << _iData_a[iIndex] << " ";
}
cout << endl;
}
int main(void)
{
CSeqList list;
for (int i = 0; i < 12; ++i)
{
list.Insert(0, i);
}
list.PrintList();
return 0;
}