数据结构03-线性表之顺序表

第三章 线性表之顺序表

  • 第三章 线性表之顺序表
    • 一、什么是线性表?
      • 1> 概念
      • 2> 线性表的基本操作
    • 二、线性表的顺序存储
        1. 存储结构
        • 顺序存储图示
        1. 核心操作
        • 1> 初始化
          • 顺序表初始化图示
          • C 语言实现
        • 2> 清空
          • 顺序表清空图示
          • C 语言实现
        • 3> 销毁
          • 顺序表销毁图示
          • C 语言实现
        • 4> 插入
          • 顺序表插入图示
          • C 语言实现
        • 5> 删除
          • 顺序表删除图示
          • C 语言实现
        • 6> 随机访问
          • C 语言实现
        1. 总结

一、什么是线性表?

1> 概念

线性表: n 个元素的有序序列。n 可为 0,表示空表;n > 0 时,除了头元素,每个元素都有后继元素,除了尾元素,每个元素都有前驱元素。换句俗话,就是说线性表中有 n 个元素,它们按顺序串成一串儿。

线性表的特点:

  1. 同一性:线性表的元素都属于同一类型;
  2. 有穷性:线性表由有限个数据元素组成,表长度就是表中数据元素的个数;
  3. 有序性:线性表中元素有序。

2> 线性表的基本操作

线性表的抽象数据型规定了线性表的基本操作,它们相当于线性表的接口。基本操作只考虑功能,不考虑实现;不同的存储方式下,实现相同的功能算法也不同;后续我们将采用不同的存储方式实现这些基本操作。

  1. InitList(&L)
    • 结果:构造一个空的线性表 L
  2. DestroyList(&L)
    • 前提:线性表 L 已存在
    • 结果:将 L 销毁
  3. ClearList(&L)
    • 前提:线性表 L 已存在
    • 结果:将 L 置为空表
  4. EmptyList(&L)
    • 前提:线性表 L 已存在
    • 结果:如果 L 为空表,则返回 TRUE,否则,返回 FALSE
  5. ListLength(L)
    • 前提:线性表 L 已存在
    • 结果:返回表中的元素个数
  6. GetElem(L, i, &e)
    • 前提:表 L 存在,且 0 <= i <= ListLength(L) - 1
    • 结果:用 e 返回 L 中第 i 个数据元素
  7. LocateElem(L, e, compare())
    • 前提:表 L 存在,compare 是数据元素的判定函数
    • 结果:返回 L 中第 1 个与 e 满足关系 compare() 的数据元素的位序,如果 e 不存在,在返回 0
  8. PriorElem(L, cur_e, &pre_e)
    • 前提:线性表已存在
    • 结果:若 cur_e 是 L 的数据元素,且不是第一个,则用 pre_e 返回它的前驱,否则操作失败,pre_e 无定义
  9. NextElem(L, cur_e, &next_e)
    • 前提:线性表已存在
    • 结果:若 cur_e 是 L 的数据元素,且不是最后一个,则用 next_e 返回它的前驱,否则操作失败,next_e 无定义
  10. ListInsert(&L, i, e)
    • 前提:表 L 已存在,e 为合法元素值且 0 <= i <= ListLength(L)
    • 结果:在 L 中第 i 个位置之前插入新的数据 e,L 的长度加 1
  11. ListDelete(&L, i, &e)
    • 前提:表 L 存在且非空,0 <= i <= ListLength(L) - 1
    • 结果:删除 L 的第 i 个数据元素,并用 e 返回其值,L 的长度减 1
  12. ListTranverse(L, visit())
    • 前提:表 L 存在
    • 结果:依次对 L 的每个数据元素调用 visit(),一旦 visit() 失败则操作失败

二、线性表的顺序存储

线性表的顺序存储 是指用一组地址连续的存储单元存储数据,使得逻辑上相邻的元素在物理上也是相邻的。

1. 存储结构

我们可以使用一维数组来存储一个线性表的元素,具体如下:

// 缓冲区初始大小
#define LIST_INIT_SIZE  100
// 缓冲区增量
#define LIST_INCREMENT  10
// 顺序表结构
typedef struct
{
    char    *elem;     // 线性表存储空间基址,为简便起见,我们让线性表存储单个字符
    int     length;    // 线性表中元素个数
    int     listsize;  // 当前分配的存储容量
} SeqList;

顺序存储图示

顺序表

2. 核心操作

我们详细说明顺序表的核心操作,其他操作见项目代码。

1> 初始化

申请顺序表空间,初始化变量。

顺序表初始化图示
顺序表初始化
C 语言实现
// 前提:L 为未初始化的线性表
// 结果:将 L 初始化为空表
Status    InitList(SeqList& L)
{   // 开辟顺序表的初始存储空间,即:缓冲区空间
    L.elem = (char*) malloc(LIST_INIT_SIZE * sizeof(char));
    if(!L.elem)
    { // 如果申请失败,返回错误代码
        printf("存储分配失败\n");
        return OVERFLOW;
    }
    L.length = 0;                 // 设置元素个数为 0
    L.listsize = LIST_INIT_SIZE;  // 设置初始缓冲区大小
    return OK;                    // 初始化成功
}

2> 清空

将当前顺序表中数据清除,保持原有存储结构;此时缓冲区大小 L.listsize 不做改变,也就是说,缓冲区大小是可以大于初始大小 LIST_INIT_SIZE 的。

顺序表清空图示
顺序表清空
C 语言实现
// 前提:线性表 L 已存在
// 结果:将 L 置为空表
void    ClearList(SeqList &L)
{
    // 将顺序表缓冲区中的数据清零
    if(L.elem)
        memset(L.elem, 0, sizeof(char) * L.listsize);
    // 将顺序表长度置 0
    L.length = 0;
}

3> 销毁

将顺序表销毁,释放所有占用的内存。

顺序表销毁图示
顺序表销毁
C 语言实现
// 前提:线性表 L 已存在
// 结果:将 L 销毁
void    DestroyList(SeqList &L)
{
    if(L.elem)
    {
        free(L.elem);
        L.elem = NULL;
    }
    L.length = 0;
    L.listsize = 0;
}

4> 插入

在顺序表中的指定位置 i (0 <= i <= L.length) 插入元素 e。

顺序表插入图示
顺序表插入
C 语言实现
// 前提:表 L 已存在,e 为合法元素值且 0 <= i <= ListLength(L)
// 结果:在 L 中第 i 个位置之前插入新的数据 e,L 的长度加 1,
//       插入成功返回 TRUE,否则,返回 FALSE
int ListInsert(SeqList &L, int i, char e)
{   // 判断插入位置是否合法
    if(i < 0 || i > L.length)
        return ERROR; // 地址错误
    // 判断缓冲区是否充足
    if(L.length >= L.listsize)
    {   // 缓存区长度不够,扩大容量,让缓冲区增加 LIST_INCREMENT
        char *buf = (char*) realloc(L.elem, (L.listsize + LIST_INCREMENT) * sizeof(char));
        if(!buf) return OVERFLOW;
        // 重置缓冲区指针
        L.elem = buf;
        // 重置缓冲区大小
        L.listsize += LIST_INCREMENT;
    }
    // pos 指向下标为 i 的元素
    char *pos = &(L.elem[i]);
    // p 从最后一个数据元素 L.elem[L.length - 1] 开始,依次递减,直到下标为 i 的元素
    for(char *p = &(L.elem[L.length - 1]); p >= pos; p--)
        *(p + 1) = *p;  // 将当前元素向后移动一个位置
    *pos = e;     // 将新增元素放在 pos 所指位置
    L.length++;   // 元素个数加 1
    return OK;
}

5> 删除

将顺序表中指定位置的元素删除。

顺序表删除图示
顺序表删除
C 语言实现
// 删除表中元素
// 前提:表 L 存在且非空,0 <= i <= ListLength(L) - 1
// 结果:删除 L 的第 i 个数据元素,并用 e 返回其值,L 的长度减 1
int ListDelete(SeqList &L, int i, char &e)
{
    // 判断删除位置是否合法
    if(i < 0 || i >= L.length)  return ERROR;
    // p 指向下标为 i 的元素
    char *p = &L.elem[i];
    // 将下标为 i 的元素放入 e 以便返回
    e = *p;
    // 从 p + 1 开始,到 L.elem[L.length - 1],将每个元素向前移动一个位置
    for(p++; p < L.elem + L.length; p++)
        *(p - 1) = *p;
    L.length--; // 元素个数减 1

    return OK;
}

6> 随机访问

获取线性表中指定位置 i (0 <= i <= L.length - 1) 的元素值。

C 语言实现
// 前提:表 L 存在,且 0 <= i <= ListLength(L) - 1
// 结果:用 e 返回 L 中第 i 个数据元素,
// 如果失败,返回 ERROR;否则,返回 OK
int GetElem(SeqList &L, int i, char *e)
{   // 判断位置是否合法
    if(i < 0 || i >= L.length)
        return ERROR;
    // 将下标为 i 的元素放入 e 以便返回
    *e = L.elem[i];
    return OK;
}

3. 总结

  1. 顺序表随机访问时,效率比较高,直接就可以访问到,时间为:O(1)
  2. 顺序表插入和删除时,为了保持顺序结构,需要移动大量的元素,因此效率很差,时间复杂度为:O(n)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容