一、什么是顺序表?

使用顺序存储方式的顺序表即为顺序表,存取时间性能为 O(1),示意图如下所示:

二、顺序表的基本操作(用静态数组实现)

在编写顺序表的基本操作函数前,有几个注意点:

  • 插入操作中,需考虑顺序表已满的情况,删除、获取操作中,需考虑顺序表为空的情况;
  • 在各操作中,当涉及到位置 i 时,都应考虑 i 位置不合理的情况;
  • 插入删除操作中,均应考虑插入或删除位置为表尾(或表尾下一个位置)的情况;

2.1 顺序表的结构定义

既然顺序表的每个数据元素的类型都相同,所以可以用 C 语言的一维数组来实现顺序存储结构,即把第一个数据元素存到数组下标为 0 的位置中,接着把顺序表相邻的元素存储在数组中相邻的位置。

来看(静态顺序)顺序表的顺序存储的结构定义。

#define MAX_SIZE 100  /* 数组长度 */
typedef int ElemType; /* "ElemType类型根据实际情况而定, 这里假设为int */
// 顺序表结构定义
typedef struct
{
ElemType data[MAX_SIZE]; /* 存放顺序表元素的数组,最大值为MAXSIZE */
int length; /* 顺序表的当前长度 */
}SeqList;

这里,我们发现顺序存储结构需要三个属性:

  • 存储空间的起始位置:数组 data,它的存储位置就是存储空间的存储位置。
  • 顺序表的最大存储容量:数组长度 MaxSize。
  • 顺序表的当前长度:length。

注意:这里有两个概念 "数组的长度" 和 "顺序表的长度" 需要区分一下。数组的长度是存放顺序表的存储空间的长度,存储分配后这个量是一般是不变的。顺序表的长度是顺序表中数据元素的个数,随着顺序表插入和删除操作的进行,这个量是变化的。

2.2 初始化操作

实现代码如下:

// 初始化操作
SeqList *initList()
{
SeqList *pSeqList = (SeqList *)malloc(sizeof(SeqList));
if (pSeqList == NULL)
{
printf("initList malloc error!\n");
exit(-1);
} pSeqList->length = 0;
return pSeqList;
}

2.3 插入操作

插入数据的实现过程如下图所示:

插入算法的思路;

  • 判断顺序表是否已满,且插入位置是否合理;
  • 从最后一个元素开始向前遍历到第 i 个位置,分别将它们都向后移动一个位置;
  • 将要插入元素填入位置i处;
  • 表长加1。

实现代码如下:

// 插入元素操作
Status insertList(SeqList *pSeqList, int i, const ElemType e)
{
// 判断顺序表是否已满,且插入位置是否合理
if (pSeqList->length >= MAX_SIZE || i < 0 || i > pSeqList->length) // 可以在表尾的下一个位置插入元素
return FALSE; // 从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置
// 这种特殊情况不用后移:在表尾的下一个位置插入元素(包含第一次在位置0插入元素的情况)
if (i != pSeqList->length)
{
// 将插入位置及后面元素向后移动一位
for (int k = pSeqList->length - 1; k >= i; k--)
pSeqList->data[k + 1] = pSeqList->data[k];
} // 将要插入元素填入位置i处
pSeqList->data[i] = e;
// 表长加1
pSeqList->length++; return TRUE;
}

2.4 删除操作

顺序表的顺序存储结构删除元素的过程如下图所示:

删除算法的思路:

  • 判断顺序表是否已满,且插入位置是否合理;
  • 取出删除元素;
  • 从删除元素的下一个位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置;
  • 表长减1。

实现代码如下:

// 删除元素操作
Status deleteList(SeqList *pSeqList, int i, ElemType *e)
{
// 判断顺序表是否为空,且删除位置是否合理
if (pSeqList->length == 0 || i < 0 || i > pSeqList->length - 1)
return FALSE; // 取出删除元素
*e = pSeqList->data[i]; // 从删除元素的下一个位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置
// 这种特殊情况不用前移:删除位置在表尾
if (i != pSeqList->length - 1)
{
// 将删除元素的下一个位置及后面元素向前移动一位
for (int k = i; k < pSeqList->length - 1; k++)
pSeqList->data[k] = pSeqList->data[k + 1];
} // 表长减1
pSeqList->length--; return TRUE;
}

2.5 获取元素操作

对于顺序表的顺序存储结构来说,如果我们要实现 getElem 操作,即将顺序表中的第 i 个位置元素值返回,其实是非常简单的。 只要 i 的数值在数组下标范围内,就是把数组第 i 下标的值返回即可。 来看代码:

// 获取元素操作
Status getElem(SeqList *pSeqList, int i, ElemType *e)
{
// 判断顺序表是否存在,且删除位置是否合理
if (pSeqList == NULL || i < 0 || i > pSeqList->length - 1)
return FALSE; *e = pSeqList->data[i]; return TRUE;
}

三、完整程序

#include <stdio.h>
#include <stdlib.h> #define TRUE 1
#define FALSE 0
typedef int Status; // Status是函数结果状态,成功返回TRUE,失败返回FALSE #define MAX_SIZE 100 /* 数组长度 */
typedef int ElemType; /* "ElemType类型根据实际情况而定, 这里假设为int */
// 顺序表结构定义
typedef struct
{
ElemType data[MAX_SIZE]; /* 存放顺序表元素的数组,最大值为MAXSIZE */
int length; /* 顺序表的当前长度 */
}SeqList; SeqList *initList(); // 初始化操作
Status appendList(SeqList *pSeqList, const ElemType e); // 附加元素操作
Status insertList(SeqList *pSeqList, int i, const ElemType e); // 插入元素操作
Status deleteList(SeqList *pSeqList, int i, ElemType *e); // 删除元素操作
Status getElem(SeqList *pSeqList, int i, ElemType *e); // 获取元素操作
int locateElem(SeqList *pSeqList, const ElemType e); // 查找元素位置操作
void traverseList(SeqList *pSeqList); // 遍历顺序表
Status isEmpty(SeqList *pSeqList); // 检测是否为空操作
int getLength(SeqList *pSeqList); // 获取元素个数操作
void clearList(SeqList *pSeqList); // 清空顺序表操作
void destroyList(SeqList *pSeqList); // 销毁顺序表操作 // 初始化操作
SeqList *initList()
{
SeqList *pSeqList = (SeqList *)malloc(sizeof(SeqList));
if (pSeqList == NULL)
{
printf("initList malloc error!\n");
exit(-1);
} pSeqList->length = 0;
return pSeqList;
} // 附加元素操作
Status appendList(SeqList *pSeqList, const ElemType e)
{
// 判断顺序表长度是否大于等于数组长度,是则抛出异常或动态增加容量
if (pSeqList->length >= MAX_SIZE)
return FALSE; // 在表尾后面添加元素e
pSeqList->data[pSeqList->length] = e; // 表长加1
pSeqList->length++; return TRUE;
} // 插入元素操作
Status insertList(SeqList *pSeqList, int i, const ElemType e)
{
// 判断顺序表是否已满,且插入位置是否合理
if (pSeqList->length >= MAX_SIZE || i < 0 || i > pSeqList->length) // 可以在表尾的下一个位置插入元素
return FALSE; // 从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置
// 有两种特殊情况不用后移:当第一次在位置0插入元素,或者在表尾的下一个位置插入元素
if (!(pSeqList->length == 0 || i == pSeqList->length))
{
// 将插入位置及后面元素向后移动一位
for (int k = pSeqList->length - 1; k >= i; k--)
pSeqList->data[k + 1] = pSeqList->data[k];
} // 将要插入元素填入位置i处
pSeqList->data[i] = e;
// 表长加1
pSeqList->length++; return TRUE;
} // 删除元素操作
Status deleteList(SeqList *pSeqList, int i, ElemType *e)
{
// 判断顺序表是否为空,且删除位置是否合理
if (pSeqList->length == 0 || i < 0 || i > pSeqList->length - 1)
return FALSE; // 取出删除元素
*e = pSeqList->data[i]; // 从删除元素的下一个位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置
if (i != pSeqList->length - 1) // 【若删除位置在表尾,则不需要前移】
{
// 将删除元素的下一个位置及后面元素向前移动一位
for (int k = i; k < pSeqList->length - 1; k++)
pSeqList->data[k] = pSeqList->data[k + 1];
} // 表长减1
pSeqList->length--; return TRUE;
} // 获取元素操作
Status getElem(SeqList *pSeqList, int i, ElemType *e)
{
// 判断顺序表是否存在,且删除位置是否合理
if (pSeqList == NULL || i < 0 || i > pSeqList->length - 1)
return FALSE; *e = pSeqList->data[i]; return TRUE;
} // 查找元素位置操作
int locateElem(SeqList *pSeqList, const ElemType e)
{
// 遍历并显示顺序表元素
for (int i = 0; i < pSeqList->length; i++)
{
if (pSeqList->data[i] == e)
return i;
} return -1;
} // 遍历操作
void traverseList(SeqList *pSeqList)
{
for (int i = 0; i < pSeqList->length; i++)
printf("%d ", pSeqList->data[i]);
printf("\n");
} // 检测是否为空操作
Status isEmpty(SeqList *pSeqList)
{
return pSeqList->length == 0 ? TRUE : FALSE;
} // 获取元素个数操作
int getLength(SeqList *pSeqList)
{
return pSeqList->length;
} // 清空顺序表操作
void clearList(SeqList *pSeqList)
{
pSeqList->length = 0;
} // 销毁顺序表操作
void destroyList(SeqList *pSeqList)
{
free(pSeqList);
pSeqList = NULL;
} int main()
{
// 初始化顺序表
SeqList *pSeqList = initList(); // 检测顺序表是否为空
if (isEmpty(pSeqList))
printf("顺序表为空!\n\n");
else
printf("顺序表不为空!\n\n"); // 附加元素0-2到顺序表
printf("附加元素0-2到顺序表!\n\n");
for (int i = 0; i<3; i++)
{
appendList(pSeqList, i);
}
printf("\n"); // 在位置2插入元素到顺序表
printf("在位置2插入元素9到顺序表!\n\n");
insertList(pSeqList, 2, 9); // 在顺序表中删除元素
int value1;
if (deleteList(pSeqList, 3, &value1) == FALSE)
{
printf("delete error!\n\n");
return -1;
}
printf("在位置3删除元素,删除的元素为:%d\n\n", value1); // 获取元素个数
printf("当前元素个数为%d个\n\n", getLength(pSeqList)); // 查找元素位置
printf("查找到元素0的位置为:%d\n\n", locateElem(pSeqList, 0)); // 遍历并显示顺序表元素
printf("遍历顺序表: ");
traverseList(pSeqList);
printf("\n"); // 清空顺序表
clearList(pSeqList);
printf("清空顺序表!\n"); // 销毁顺序表
destroyList(pSeqList);
printf("\n"); return 0;
}

输出结果如下图所示:

注意上面只是 “静态顺序表” 的 C 语言实现,只实现了一些基本操作,有兴趣的同学可以在这上面扩展;另外测试编译器为 VS2013。

参考:

《大话数据结构 - 第3章》 顺序表

数据结构 - 静态顺序线性表的实行(C语言)的更多相关文章

  1. C语言数据结构-顺序线性表的实现-初始化、销毁、长度、查找、前驱、后继、插入、删除、显示操作

    1.数据结构-顺序线性表的实现-C语言 #define MAXSIZE 100 //结构体定义 typedef struct { int *elem; //基地址 int length; //结构体当 ...

  2. 顺序线性表 ---- ArrayList 源码解析及实现原理分析

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7738888.html ------------------------------------ ...

  3. 线性表&顺序线性表

    第二章 线性表 参考文献:[数据结构(C语言版)].严蔚敏 本篇章仅为个人学习数据结构的笔记,不做任何用途. 2.1 线性结构的特点 (1). 存在唯一的一个被称为"第一个"的数据 ...

  4. C++ 数据结构 1:线性表

    1 数据结构 1.1 数据结构中基本概念 数据:程序的操作对象,用于描述客观事物. 数据的特点: 可以输入到计算机 可以被计算机程序处理 数据是一个抽象的概念,将其进行分类后得到程序设计语言中的类型. ...

  5. 顺序线性表之大整数求和C++

    顺序线性表之大整数求和 大整数求和伪代码 1.初始化进位标志 flag=0: 2.求大整数 A 和 B 的长度: int aLength = a.GetLength(); int bLength = ...

  6. 顺序线性表之大整数求和C++实现

    顺序线性表之大整数求和 大整数求和伪代码 1.初始化进位标志 flag=0: 2.求大整数 A 和 B 的长度: int aLength = a.GetLength(); int bLength = ...

  7. 基于c语言数据结构+严蔚敏——线性表章节源码,利用Codeblocks编译通过

    白天没屌事,那我们就来玩玩线性表的实现吧,快要失业了,没饭吃了咋整哦 题目描述假设利用两个线性表LA和LB分别表示两个集合A和B(即:线性表中的数据元素即为集合中的成员),现要求一个新的集合A=A∪B ...

  8. PHP数据结构之二 线性表中的顺序表的PHP实现

    线性表 (一)基本特点:最基本.最简单.最常用的一种数据结构 在这种结构中: 1.存在一个唯一的被称为“第一个”的数据元素: 2.存在一个唯一的被称为“最后一个”的数据元素: 3.除第一个元素外,每个 ...

  9. 动态分配的顺序线性表的十五种操作—C语言实现

    线性表 定义:是最常用的,也是最简单的数据结构,是长度为n个数据元素的有序的序列. 含有大量记录的线性表叫文件 记录:稍微复杂的线性表里,数据元素为若干个数据项组成,这时把一个数据元素叫记录 结构特点 ...

随机推荐

  1. Git入门使用

    Git入门使用 安装Git 软件包如: Git-2.7.2-32-bit_setup.1457942412.exe TortoiseGit-1.8.12.0-64bit.msi 安装时候,直接点下一步 ...

  2. Semaphore使用

    Semaphore使用

  3. 关键路径(AOE)---《数据结构》严蔚敏

    // exam1.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> #include &l ...

  4. enumerateObjectsUsingBlock 、for 、for(... in ...) 的差别 &amp; 性能測试

    for VS for(... in ...) for 的应用范围广基本能够NSArray.NSArray以及C语言的数组等,而for(... in ...)仅限于NSArray.NSArray等 fo ...

  5. C++ std::tr1::shared_ptr使用说明

    1. 介绍 shared_ptr 是通过指针保持某个对象的共享拥有权的智能指针. 若干个 shared_ptr 对象能够拥有同一个对象:最后一个指向该对象的 shared_ptr 被销毁或重置时.该对 ...

  6. Hibernate4之session核心方法

    在学习session的核心方法之前,我们先了解下hibernate中几种对象的状态: 暂时状态:这样的状态就好像咱们公司请的暂时员工一样,他在公司里没有相关的资料和id. 特点:在使用代理主键的情况下 ...

  7. vim、gvim在windows下中文乱码的终极解决方式

    測试成功,完美解决. 仅仅需改动VIM文件夹以下的这个文件_vimrc. 加油吧,骚年.非常强大的! set encoding=utf-8 set fileencodings=utf-8,chines ...

  8. JavaScript-创建第一个自己的类库

    通过上一节面向对象和原型的学习. 我们知道了怎样创建一个类,包含类的私有化属性和方法.公有化属性和方法.静态属性和方法.在这里略微回想一下.首先要创建一个类能够通过1.new object().2.利 ...

  9. setTimeout不可靠的修正办法及clearTimeout

    javascript里的这两个定时器函数,大家一定耳熟能详: setTimeout("函数()",毫秒)就是开启一个计时器,指定毫秒后执行该函数一次. 有关定时器,javascri ...

  10. 2016/05/11 Thinkphp 3.2.2 验证码 使用 及校验

    先新建一个公共控制器,用于放置验证码的实例化代码(不用新建控制器也行,任意公共控制器都可以). 例如:PublicController.class.php 4 5 6 7 8 9 10 11 12 1 ...