一、什么是顺序表?

使用顺序存储方式的顺序表即为顺序表,存取时间性能为 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. 图解TCP/IP第五版 -- 文件夹

    非常多年前买过<TCP/IP具体解释>3卷,当时可能根本没看,也可能是看了又忘了,没有留下什么印象,当时的书也当做废品卖了. 卖书时的感觉貌似是.买了太多的书,基本都没看,搬家搬来搬去的麻 ...

  2. hive计算网页停留时长

    hive表结构例如以下: create table pv_user_info( session_id string, user_id string, url string, starttime big ...

  3. Servlet第七课:ServletContext HttpSession 以及HttpServletRequest之间的关系

    课程目标: ① 在Servlet中懂得ServletContext HttpSession 以及HttpServletRequest之间的关系 ② 懂得怎样使用它们 概念介绍: 1. [共同点]不管对 ...

  4. Servlet的引入

    一.分析 此模式有问题: 1.jsp需要呼叫javabean StudentService stuService = new StudentServiceImpl(); List<Student ...

  5. EJB学习笔记六(EJB中的拦截器)

     1.前言 听到拦截器,预计都不陌生,尤其是在Servlet规范中,充分应用了拦截器的概念.EJB3也提供了拦截器的支持,本质上是轻量级的AOP实现.拦截器能够将多个业务方法中的通用逻辑从业务方法中抽 ...

  6. ubuntu查看文件的权限

    查看linux文件的权限: 查看path路径下名为filename的文件或文件夹的权限: ls -l path/filename ls -l path/filename 查看path路径下的所有文件的 ...

  7. leetcode 659. Split Array into Consecutive Subsequences

    You are given an integer array sorted in ascending order (may contain duplicates), you need to split ...

  8. Lightoj 1011 - Marriage Ceremonies

    You work in a company which organizes marriages. Marriages are not that easy to be made, so, the job ...

  9. YTU 1010: 目标柏林

    1010: 目标柏林 时间限制: 1000 Sec  内存限制: 64 MB 提交: 32  解决: 15 题目描述 1945年初,苏军和英美联军已从东西两面攻入德国国境. 4月初,在苏军和英美联军的 ...

  10. YTU 2953: A代码填充--学画画

    2953: A代码填充--学画画 时间限制: 1 Sec  内存限制: 128 MB 提交: 62  解决: 52 题目描述 最近小平迷上了画画,经过琨姐的指导,他学会了RGB色彩的混合方法.对于两种 ...