C语言实现顺序表

这篇具有很好参考价值的文章主要介绍了C语言实现顺序表。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

顺序表

1.线性表

线性表是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。

C语言实现顺序表,数据结构,c++,数据结构,c语言,算法

2.顺序表

顺序表的概念

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

顺序表一般可以分为:

1. 静态顺序表:使用定长数组存储元素。

C语言实现顺序表,数据结构,c++,数据结构,c语言,算法

2.动态顺序表:使用动态开辟的数组存储。

C语言实现顺序表,数据结构,c++,数据结构,c语言,算法

顺序表的接口实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间 大小,所以下面我们实现动态顺序表。

接口如下:

// 对数据的管理:增删查改
void SeqListInit(SeqList* ps);                    // 顺序表的初始化
void SeqListDestroy(SeqList* ps);                 // 顺序表的销毁
void SeqListPrint(SeqList* ps);                   // 顺序表的打印
void Check_Capacity(SeqList* ps);                 // 检查是否需要扩容
void SeqListPushBack(SeqList* ps, SLDataType x);  // 顺序表的尾插
void SeqListPushFront(SeqList* ps, SLDataType x); // 顺序表的头插
void SeqListPopFront(SeqList* ps);                // 顺序表的头删
void SeqListPopBack(SeqList* ps);                 // 顺序表的尾删

// 顺序表查找
int SeqListFind(SeqList* ps, SLDataType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos);
//修改指定下标位置元素
void SeqListModify(SeqList *ps, int pos, SLDataType x);

初始化顺序表

首先,我们要创建一个顺序表类型,该顺序表类型包括了顺序表的起始位置、记录顺序表内已有元素个数的计数器(size),以及记录当前顺序表的容量的变量(capacity)。

typedef int SLDataType;   //顺序表类型
typedef struct SeqList   // 顺序表的结构(动态)
{
    SLDataType* a;		//声明了一个指向顺序表的指针,姑且称它为“顺序表指针”
    int size; 			//记录当前顺序表内元素个数
    int capacity;		//记录当前顺序表的最大容量
} SeqList;

然后,我们需要一个初始化函数,对顺序表进行初始化。

// 顺序表的初始化
void SeqListInit(SeqList *ps) {
    assert(ps);		//断言,ps不能为NULL
    ps->a = NULL;   //刚开始时顺序表为空,顺序表指针为NULL
    ps->size = 0;	//起始时元素个数为0
    ps->capacity = 0;	//容量为0
}

销毁顺序表

因为顺序表所用的内存空间是动态开辟在堆区的,所以我们在使用完后需要及时对其进行释放,避免造成内存泄漏

// 顺序表的销毁
void SeqListDestroy(SeqList *ps) {
    assert(ps);
    free(ps->a);//释放顺序表指针指向的空间
    ps->a = NULL;
    ps->size = 0;    //元素个数置0
    ps->capacity = 0;//容量置0
}

顺序表打印

// 顺序表的打印
void SeqListPrint(SeqList *ps) {
    assert(ps);
	//循环遍历顺序表
    for (int i = 0; i < ps->size; i++) {
        printf("%d ", ps->a[i]);
    }
    printf("\n");
}

插入数据

仔细想想,我们每次需要增加数据的时候,首先都应该先检查顺序表内元素个数是否已达顺序表容量上限。若已达上限,那么我们就需要先对顺序表进行扩容,然后才能增加数据。

检查容量
// 扩容
void Check_Capacity(SeqList *ps) {
    if (ps->capacity == ps->size) {
        // 如果容量等于大小说明满了需要扩容   如果size和capacity为0,说明是初始化状态,默认给4个字节,否则就扩容两倍
        int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
        // 将扩容的指针放到临时变量中
        SLDataType *tmp = (SLDataType *) realloc(ps->a, sizeof(SLDataType) * newcapacity);
        //	若传入realloc的指针为空指针(NULL),则realloc函数的作用相当于malloc函数。
        if (tmp == NULL) {
            perror("realloc fail");
            exit(-1);
        } else {
            ps->a = tmp;
            ps->capacity = newcapacity;
        }
    }
}
头插

要想在顺序表的表头插入数据,那么就需要先将顺序表原有的数据从后往前依次向后挪动一位,最后再将数据插入表头。

// 顺序表的头插
void SeqListPushFront(SeqList *ps, SLDataType x) {
	assert(ps);
	Check_Capacity(ps);   //检查容量
	// 头插-插入到顺序表的最开始的位置,下标是0,但是需要挪动整个顺序表
	for (int i = ps->size; i >= 0; i--) // 将所有数据挪动到下一个位置
	{
		// size的下标是最后位置的下一个
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[0] = x;
	ps->size++;
}
尾插

尾插相对于头插就比较简单了,直接在表尾插入数据即可。

// 顺序表的尾插
void SeqListPushBack(SeqList *ps, SLDataType x) {
	assert(ps);
	Check_Capacity(ps);
	// 尾插-插入到顺序表中的下一个位置,下标也就是ps->size
	ps->a[ps->size] = x;
	ps->size++;
}
指定位置插入

要做到在指定下标位置插入数据,首先我们需要得到一个下标位置,然后从该下标位置开始(包括该位置),其后的数据从后往前依次向后挪动一位,最后将数据插入到该下标位置。pos默认从1开始。

// 顺序表在pos位置插入x,
void SeqListInsert(SeqList *ps, int pos, SLDataType x) {
    pos--;//pos对应数组下标,pos默认从1开始。
    assert(ps);
    assert(pos >= 0 && pos <= ps->size);
    Check_Capacity(ps);
    //将pos后面的数据向后挪动一个位置
    for (int i = ps->size; i > pos; i--) {
        ps->a[i] = ps->a[i - 1];
    }

    ps->a[pos] = x;
    ps->size++;
}

我们可以发现,头插和尾插实际上就是在下标为0的位置和下标为ps->size的位置插入数据,也就意味着我们可以统一使用该函数来实现头插和尾插。

// 顺序表的尾插
void SeqListPushBack(SeqList *ps, SLDataType x) {
    SeqListInsert(ps, ps->size + 1, x);//+1 是对应逻辑下标,pos位置默认从1开始
}

// 顺序表的头插
void SeqListPushFront(SeqList *ps, SLDataType x) {
    SeqListInsert(ps, 1, x);			//1是逻辑下标,真实下标是0
}

删除数据

头删

要删除表头的数据,我们可以从下标为1的位置开始,依次将数据向前覆盖即可。

// 顺序表的头删
void SeqListPopFront(SeqList *ps) {
	assert(ps);
	assert(ps->size);
	// 将顺序中除了第一个位置的所有数据向前挪动一个下标
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}
尾删

尾删就更简单了,直接将顺序表的元素个数减一即可。

// 顺序表的尾删
void SeqListPopBack(SeqList *ps) {
    assert(ps);
    assert(ps->size);   //保证顺序表不为空
    ps->size--;
}
指定下标位置删除

要删除指定下标位置的数据,我们只需要从下标位置开始,其后的数据从前向后依次覆盖即可。

//顺序表删除pos位置的值
void SeqListErase(SeqList *ps, int pos) {
    pos--;//对其数组下标
    assert(ps);
    assert(pos >= 0 && pos < ps->size);
    //从pos位置开始,后面数据都向前挪动一个位置
    for (int i = pos; i < ps->size - 1; i++) {
        ps->a[i] = ps->a[i + 1];
    }
    ps->size--;
}

同样的道理,头删和尾删实际上也就是删除下标为0的位置和下标为ps->size - 1的位置的数据,也就意味着我们可以统一使用该函数来实现头删和尾删。

// 顺序表的头删
void SeqListPopFront(SeqList *ps) {
    SeqListErase(ps, 1);
}

// 顺序表的尾删
void SeqListPopBack(SeqList *ps) {
    SeqListErase(ps, ps->size);
}

查找数据

查找数据也相对简单,直接遍历一次顺序表即可,若找到了目标数据,则停止遍历,并返回该数据的下标,否则返回-1。

// 顺序表查找
int SeqListFind(SeqList *ps, SLDataType x) {
    int i = 0;
    for (i = 0; i < ps->size; i++) {
        if (ps->a[i] == x) {
            return i + 1;//i+1对应逻辑下标
        }
    }
    return -1;//找不到返回-1
}

测试代码:

#include "SeqList.h"
void Test1() {
    struct SeqList s1;
    SeqListInit(&s1);
    SeqListPushBack(&s1, 1);
    SeqListPushBack(&s1, 2);
    SeqListPushBack(&s1, 3);
    SeqListPushBack(&s1, 4);
    SeqListPrint(&s1);//1 2 3 4
    SeqListPopFront(&s1);
    SeqListPopFront(&s1);
    SeqListPrint(&s1);//3 4
    SeqListPopBack(&s1);
    SeqListPopBack(&s1);
    SeqListPrint(&s1);//
    SeqListPushFront(&s1, 0);
    SeqListPushFront(&s1, -1);
    SeqListPrint(&s1);        //-1 0
    SeqListInsert(&s1, 1, 61);//下标为1插入一个61
    SeqListInsert(&s1, 2, 62);//下标为1插入一个62
    SeqListInsert(&s1, 3, 63);//下标为1插入一个63
    SeqListInsert(&s1, 4, 64);//下标为1插入一个64
    SeqListPrint(&s1);        //61 62 63 64 -1 0
    SeqListErase(&s1, 1);
    SeqListErase(&s1, 1);
    SeqListErase(&s1, 1);
    SeqListErase(&s1, 1);
    SeqListPrint(&s1);//-1 0
    SeqListDestroy(&s1);
}

int main() {
    Test1();
    return 0;
}

修改数据

修改数据,就直接对该位置的数据进行再次赋值即可。

//修改指定下标位置元素
void SeqListModify(SeqList *ps, int pos, SLDataType x) {
    pos--;//对应数组下标
    assert(ps);
    assert(pos >= 0 && pos < ps->size);//检查输入下标的合法性
    ps->a[pos] = x;                //修改数据
}

3.顺序表的问题及思考

问题:文章来源地址https://www.toymoban.com/news/detail-684199.html

  1. 中间/头部的插入删除,时间复杂度为O(N)
  2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到 200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

到了这里,关于C语言实现顺序表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】C语言实现顺序栈

    大家好,很高兴又和大家见面啦!!! 在上一个篇章中,我们介绍了栈的基本概念,以及栈中的重要术语。通过介绍我们知道了栈的本质也是一种线性表,只不过它是一种操作受限的线性表。因此栈的实现方式与线性表的实现实际上是大同小异的。下面我们就来介绍一下如何

    2024年01月19日
    浏览(31)
  • 数据结构:定长顺序串(SString)基本操作的算法描述(C语言)

    作者在学习数据结构时,发现鲜有完全按照 C 语言描述的算法操作,这让习惯于写 .c 而不是 .cpp 的初学者很是头疼。本文将基于 C 语言描述算法操作,如有错漏还望大佬们指正。 本文将按照严惠敏所著《数据结构(C语言版)》所做的函数原型声明进行算法描述,由于C语言不支

    2024年02月07日
    浏览(54)
  • 【数据结构】C语言实现顺序表(超级详细)

    目录 概念及结构 接口函数实现 顺序表的初始化 容量判断  顺序表尾插  顺序表尾删 顺序表头插 顺序表头删 顺序表查找 顺序表指定位置插入 顺序表指定位置删除 打印顺序表 销毁顺序表 顺序表完整代码 顺序表作为线性表的一种,它是用一段 物理地址连续的存储单元依次

    2024年04月10日
    浏览(27)
  • 【数据结构与算法】之顺序表及其实现!

    目录 ​编辑 1. 顺序表的概念及结构 2. 接口的实现 2.1 顺序表的初始化 2.2 检查顺序表容量是否已满 2.3 顺序表的尾插 ​编辑 2.4 顺序表的尾删 2.5 顺序表的头插 2.6  顺序表的头删 2.7 顺序表在pos位置插入 2.8  顺序表在pos位置删除 2.9 顺序表的查找 2.10 顺序表的销毁 2.1

    2024年04月28日
    浏览(27)
  • 【C语言数据结构】模拟·顺序表·总项目实现

    💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃 个人主页 :阿然成长日记 👈点击可跳转 📆 个人专栏: 🔹数据结构与算法🔹C语言进阶 🚩 不能则学,不知则问,耻于问人,决无长进 🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍 我在上一篇博客中,

    2024年02月15日
    浏览(31)
  • 【数据结构】:实现顺序表各种基本运算的算法

    领会顺序表存储结构和掌握顺序表中各种基本运算算法设计。 编写一个程序sqlist.cpp,实现顺序表的各种基本运算和整体建表算法(假设顺序表的元素类型ElemType为char),并在此基础上设计一个主程序,完成如下功能: 初始化顺序表L 依次插入a,b,c,d,e元素 输出顺序表L 输出顺

    2024年02月07日
    浏览(34)
  • 【数据结构初阶】二、 线性表里的顺序表(C语言实现顺序表)

    ========================================================================= 相关代码gitee自取 : C语言学习日记: 加油努力 (gitee.com)  ========================================================================= 接上期 : 【数据结构初阶】一. 复杂度讲解_高高的胖子的博客-CSDN博客  =======================================

    2024年02月08日
    浏览(30)
  • 【数据结构】线性表的顺序存储结构及实现——C语言版

    线性表的顺序存储结构称为 顺序表 ,其基本思想是 用一段地址连续的存储单元一次存储线性表的数据元素。 设顺序表的每个元素占用 c 个存储单元,则第 i 个元素的存储地址为: 所以, 只要确定了存储顺序表的起始地址(即基地址),计算任意一个元素的存储地址的时间

    2024年03月15日
    浏览(40)
  • 【数据结构】C语言实现顺序栈(附完整运行代码)

    🦄 个人主页 :修修修也 🎏 所属专栏 :数据结构 ⚙️ 操作环境 : Visual Studio 2022 在本次项目中我们的目标是 实现一个 顺序栈 : 该 顺序栈 使用 动态内存分配空间 ,可以用来 存储任意数量的同类型数据 . 顺序栈 结构体 需要包含 三个要素 : 存放数据的数组arr,栈顶元素下标top

    2024年04月29日
    浏览(25)
  • 【数据结构】顺序表基本操作的实现(C语言)

    🚀 作者简介:一名在后端领域学习,并渴望能够学有所成的追梦人。 🐌 个人主页:蜗牛牛啊 🔥 系列专栏:🛹数据结构、🛴C++ 📕 学习格言:博观而约取,厚积而薄发 🌹 欢迎进来的小伙伴,如果小伙伴们在学习的过程中,发现有需要纠正的地方,烦请指正,希望能够与

    2024年02月16日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包