数据结构笔记(一)线性表 超完整~~~涵盖顺序表几乎所有操作(附有完整代码实现)

第一章 线性表

定义:由n个(n >= 0)个同一类型的数据元素构成的有限序列的线性结构

按线性关系存放数据的表,表的地址空间可以连续(顺序表,底层为数组),也可以不连续(链表,为节点链接而成,每个节点都能找到下一个节点的位置,仿佛有一条链将所有节点串起来)

一、顺序表

顺序表, 字面意义就是有顺序的表,可以连续存储数据,本质上为数组

1.1 逻辑结构

逻辑结构采用图来表示 L为指向SeqList的指针 SeqList中的array指向数据的指针

1.2 存储结构

存储结构 在计算机中定义该结构 利用代码表示

一维数组在内存中占用的存储空间就是一组连续的存储区域,数组容量需足够大

将底层的数组封装为结构体,结构成员有capacity(表的容量)和length(当前表长)

//为类型取别名 方便更改类型 
typedef int ElementType;
​
typedef struct{ //省略结构名 
    ElementType *array; //存放数据的指针
    int length;         //已有数据个数
    int capacity;       //容量
}SeqList;

讲完逻辑结构和存储结构,接下来就该说说顺序表结构的操作了

2.1 创建表

定义createSeqList()函数 实现创建表的功能 并返回指向表结构的指针

SeqList* createList(int capacity)
{
    SeqList *L = (SeqList*)malloc(sizeof(SeqList)); //动态分配
    L->length = 0;
    L->capacity = capacity;
    L->array = (ElementType*)malloc(capacity * sizeof(capacity));
    return L;
} 

使用动态分配内存的方式,先从堆区分配一块内存用于存放封装表的结构,再将L指针强制转换成SeqList结构类型,即让L指针指向表结构。同理,对结构中封装的表(数组)也是用动态分配内存的方法 sizeof(ElementType)为类型大小,乘上capacity意为分配capacity个大小为ElementType的空间,array指针指向这个空间(本质上数组也为指针)

2.2 判空

判断顺序表是否为空 若为空 返回 1 否则返回0

int isEmpty(SeqList *L)
{
    return L->length == 0;  
} 

很简短 只有一行代码 也可以使用if-else语句

2.3 输出

输出顺序表中的所有元素 (注意:空顺序表没有输出)

void printList(SeqList *L)
{
    if (!L->length) return;
    for (int i = 0; i < L->length; i ++ ) printf("%d ", L->array[i]);
    puts("");
} 

2.4 长度

返回顺序表的长度

int getLength(SeqList *L)
{
    return L->length;
}

2.5 插入

在顺序表第i个位置插入元素 插入成功返回1 否则返回0

int insertList(SeqList *L, int i, ElementType x)
{
    //顺序表已满 
    if (L->length == L->capacity) return 0; 
    //插入位置不合法 (从第一个位置开始插入) 
    if (i < 1 || i > L->length + 1) return 0;
    for (int j = L->length; j > i - 1; j -- )
        L->array[j] = L->array[j - 1];
    L->array[i - 1] = x;
    //插入数据后 表长加一 
    L->length ++ ; 
    return 1;   
}

2.6 查找

查找顺序表中值为x的元素,并返回其在顺序表中首次出现的位置 若不存在 返回-1

(第一个元素在第一个位置,但其所在下标为0)

int find(SeqList *L, ElementType x)
{
    for (int i = 0; i < L->length; i ++ )
        if (L->array[i] == x) return i + 1;
    return -1;  
}

2.7 获取数据

获取顺序表中第i个位置的数据 并让p指向它 获取成功返回-1,否则返回0

int getElement(SeqList *L, int i, ElementType *p)
{
    if (L->length == 0) return 0;
    if (i < 1 || i > L->length) return 0;
    
    *p = L->array[i - 1];
    return 1;
}

2.8 删除数据

删除顺序表中的第i个元素的数据 并让p指向被删除的数据

int delElement(SeqList *L, int i, ElementType *p)
{
    if (L->length == 0) return 0;
    if (i < 1 || i > L->length) return 0;
    *p = L->array[i - 1];
    for (int j = i - 1; j < L->length - 1; j ++ )
        L->array[j] = L->array[j + 1];
        
    L->length -- ;
    return 1;
}

删除的代码和插入的很像 注意判断删除位置是否合法与插入数据不太一样

2.9 删除重复数据

三重循环版本

void delRepeatElement(SeqList *L)
{   
    for (int i = 0; i < L->length - 1; i ++ )
        for (int j = i + 1; j < L->length; j ++ )
        {
            if (L->array[i] == L->array[j])
            {
                for (int k = j; k < L->length - 1; k ++ ) //注意覆盖元素的下标:从j开始 
                    L->array[k] = L->array[k + 1];  
                L->length -- ;
                j -- ;  
            } 
        }
}

2.10 有序合并

按从小到大的顺序合并顺序表(归并排序中的合并操作!)

void mergeList(SeqList *LA, SeqList *LB, SeqList *LC)
{
    int i = 0, j = 0, k = 0;
    
    while (i < LA->length && j < LB->length)
    {
        if (LA->array[i] <= LB->array[j]) 
            LC->array[k ++ ] = LA->array[i ++ ];
        else
            LC->array[k ++ ] = LB->array[j ++ ];
    }
    
    while (i < LA->length)
        LC->array[k ++ ] = LA->array[i ++ ];
    while (j < LB->length) 
        LC->array[k ++ ] = LB->array[j ++ ];
    
    LC->length = k; 
}

注意下标和表的对应问题 i对应LA表, j对应LB表, k对应LC表

当LA和LB都不为空时,依次比较两表中的元素,将小的元素存放到LC中

后面两个while循环只会执行其中一个,当LA或LB中还有元素时将其存入LC中

LC的长度即为下标k(k ++ 在后)

2.11 清除数据

清除数据 顺序表空间仍然保留

void clearList(SeqList *L)
{
    L->length = 0;
}

直接将L->length置为0,不释放顺序表空间

2.12 销毁

销毁整个顺序表(释放掉动态分配的内存空间)

void destroyList(SeqList *L)
{
    free(L->array);
    free(L);
}

注意在释放内存的时候应先释放最底层的内存,若先释放L,L->array的内存空间仍然保留并且无法释放

3 总结

顺序表是一种线性存储结构,最底层为数组,通过封装成为结构实现顺序表。顺序表的动态分配内存可能是初学者的难点,需要对malloc函数还有计算机内存,指针等知识有所了解。在今后数据结构的学习中,许多数据结构都是用动态分配内存的方式(当然也可以不使用动态分配)许多数据结构都是基于顺序表和链表演化而成,例如栈、队列、二叉树等,打好线性表的基础对今后的学习很有帮助。

创作不易!希望大家多多支持!保持更新到图论!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值