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

定义

线性表(list/squencelist)是零个或多个数据元素的有限序列。

线性表的特点

1.数据元素是有序

2.数据元素是一对一

 

线性表的数据集合为{a1,a2,......,an},每个元素类型均为datatype。其中除了第一个元素a1外,每个元素有且只有一个前驱元素,除an外,每个元素只有一个直接后继元素;数据元素之间是一对一的关系。

 

线性表的操作

初始化      initlist(*list)    创建一个空的线性表

插入     insertelement(*list,index,elem)    在线性表list下的index下插入elem

删除    deleteelement(*list,index,*elem)    删除线性表list中第i个元素并使用指针返回elem

求长度    getlenth(*list)

是否为空表     isempty(*list)

清空线性表     clearlist(*list)

查找    getelement(list,index,*elem)    根据下标寻找元素

            exsitelem(*l,elem,index)    寻找是否存在,将下标返回

 

顺序表

线性表的顺序存储结构,利用一段连续的内存空间(也就是c语言的数组)

1.我们需要定义线性表的最大储存空间

2.需要有统一类型的元素集合

3.需要线性表的存储位置(需要知道一个指针指向线性表)


常用算法

 

首先我们先来定义线性表

我们需要在这里讲一下c语言的头文件 以前都是使用别人写好的头文件 但是现在因为我们程序越写越大就需要去自定义头文件

 

写法1:在.h头文件中就包含函数的实现,这种头文件实际上是把函数放在一起,便于管理而已。这种情况下只有一个.h文件。

写法2:在.h头文件中只包含一些函数的声明,没有具体的实现。函数的实现放在另外一个不包含main()的.c源文件中,然后需要将源文件和头文件连接起来。这种情况下包含.h文件和.c文件两种文件。

然后将可以像包含<stdio.h>一样直接引用自定义的头文件了。如果想在其他项目中也使用,可以将其放到头文件库中。

两种写法我只实现了第一种。需要注意的是.h需要和调用.h的.c文件放在同一个文件夹即可。

具体实例如下:

.h文件包含以下函数

void hello(void)
{
    printf("hello world\n");
}
.c文件程序如下:

#include <stdio.h>
#include "test.h" //这里要注意使用自己的头文件要使用""
 
int main()
{
    hello();
    return 0;
}
 

于是我们完成了第一个头文件

#ifndef DATAELEMENT_H_INCLUDED
#define DATAELEMENT_H_INCLUDED

/**********************************************************
*  定义数据元素
**********************************************************/

#define MAX_SIZE 255
#define TRUE 1
#define FALSE 0

//1.定义数据元素
typedef struct {

    int id;
    char  * name;

}ElementType;

//2.定义顺序表结构
typedef struct{

    ElementType datas[MAX_SIZE];    //顺序表中的数据元素集合
    int length;                     //当前顺序表中的元素个数

}SeqList;

#endif // DATAELEMENT_H_INCLUDED

呢么关于ifdef 和 endif 可以看下这篇百度百科很详细

https://baike.baidu.com/item/%23ifdef/2834634?fr=aladdin

头文件一般主要放函数或变量的声明,同名cpp中放置函数具体的实现代码和变量的初始化等,使用时一般是包含头文件就可以调用相应的函数

下面我们来声明我们需要用到的函数

 

然后我们只需要引用这些头文件就相当于已经声明了这些函数和常量

插入的逻辑结构

最后将顺序表的总长度加一 

删除元素 将元素前移一个,要将顺序表长度减一 来讲前面得元素覆盖

#include "SequenceList.h"

/**
 * 初始化顺序表
 * @param seqList   要初始化的顺序表
 * @param elemArary 初始化时要添加的元素内容数组
 * @param length    初始化时添加的元素个数
 */
void InitList(SeqList * seqList, ElementType * elemArray, int length)
{
    if(length > MAX_SIZE)
    {
        printf("超出了数组的最大容量,初始化失败!\n");
        return;
    }
    seqList->length = 0;    //记得在初始化顺序表时,将顺序表的长度置零
    for(int i = 0; i < length; i++)
    {
        //每次循环都在下标为i的位置插入一个元素
        InsertElement(seqList, i, elemArray[i]);
    }
}

/**
 * 向顺序表中的index下标处插入某个元素
 * @param seqList
 * @param index     要插入的下标
 * @param element   要插入的元素
 */
void InsertElement(SeqList * seqList, int index, ElementType element)
{
    //1、验证插入后的元素空间是否超过MAX_SIZE
    //2、index的值是否合法[0, MAX_SIZE-1]
    //3、插入的index应该在length之内
    //4、从第length-1个下标开始,前面一个元素赋值给后面一个元素

    if(seqList->length + 1 >= MAX_SIZE)
    {
        printf("数组已满,插入元素失败!\n");
        return;
    }
    if(index < 0 || index > MAX_SIZE - 1)
    {
        printf("只能在允许的下标范围内插入元素[0, %d]\n", MAX_SIZE - 1);
        return;
    }
    if(index > seqList->length)
    {
        printf("插入的下标超过了数组的最大长度-1,插入失败!\n");
        return;
    }
    //在C89标准中不允许在for中直接定义变量
    //C99中以后就允许了
    for(int i = seqList->length - 1; i >= index; i--)
    {
        seqList->datas[i + 1] = seqList->datas[i];
    }
    //5、将要插入的值赋给第index个元素
    seqList->datas[index] = element;
    //6、顺序表的总长度+1 !!!! - 非常容易漏掉的地方
    seqList->length++;
}

/**
 * 删除顺序表中指定下标的元素
 * @param seqList   要操作的顺序表
 * @param index     要删除的下标
 * @return 返回删除的元素,如果删除失败,返回NULL(建议使用完毕后进行free,否则会造成内存泄露)
 */
ElementType * DeleteElement(SeqList * seqList, int index)
{
    if(index < 0 || index > MAX_SIZE - 1)
    {
        printf("下标越界,无法删除指定下标的元素!\n");
        return NULL;
    }
    //1.找到要删除的元素,并保存起来以便返回(保存的是已删除元素的副本!!!!)
    ElementType * delElement = (ElementType *)malloc(sizeof(ElementType));
    //单独定义并调用查找函数,返回要删除元素的指针
    *delElement = *GetElement(seqList, index);
    //2.从指定位置删除,后面一个元素赋值给前面一个元素
    for(int i = index; i < seqList->length - 1; i++)
    {
        seqList->datas[i] = seqList->datas[i + 1];
    }
    //3.顺序表的总长度-1
    seqList->length--;
    return delElement;  //建议使用完毕后进行free,否则会造成内存泄露
}

/**
*将指针释放
**/
/*int free_p(ElementType * p)
{
    if(p == NULL)
    {
        return -1;
    }
    free(p);
    delElement = NULL;
    return 0;
}*/
/*在使用完返回的delelement使用此函数将其释放

/**
 * 返回顺序表中指定下标的元素
 * @param seqList   要操作的顺序表
 * @param index     要返回元素的下标
 * @return 返回指定下标的元素,如果查找失败,返回NULL
 */
ElementType * GetElement(SeqList * seqList, int index)
{
    if(index < 0 || index > MAX_SIZE - 1)
    {
        printf("下标越界,无法找到指定下标的元素!\n");
        return NULL;
    }
    ElementType * element;  //要查找的元素
    element = &seqList->datas[index];
}

/** 返回顺序表的长度 */
int GetLength(SeqList * seqList)
{
    if(seqList == NULL)
        return 0;
    return seqList->length;
}

/** 返回顺序表是否为空 */
int IsEmpty(SeqList * seqList)
{
    return GetLength(seqList) == 0 ? TRUE : FALSE;
}

/** 清空顺序表 */
void ClearList(SeqList * seqList)
{
    if(seqList == NULL) return;
    seqList->length = 0;
}

void PrintList(SeqList * seqList)
{
    for(int i = 0; i < seqList->length; i++){
        printf("%d\t%s\n", seqList->datas[i].id, seqList->datas[i].name);
    }
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值