【数据结构】【王道】【线性表】顺序表实现及基本操作(可直接运行)

总目录


各部分的解释已经以注释形式写于代码中。

1.顺序表简介

顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系,采用顺序存储结构的线性表通常称为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。
在这里插入图片描述

2.动态分配

动态分配是指分配的空间大小可以在运行时动态决定。

2.1 表的定义

typedef struct {
    int* data;  // 指向动态分配顺序表的指针
    int MaxSize;    // 顺序表最大容量
    int length; // 顺序表当前长度
} SeqList;

2.2 初始化

// 初始化
void InitList(SeqList &L) {
    // 用malloc函数申请一片连续的存储空间
    // 注意:前面部分的强转不能忘记,否则会出错,应转成对应类型的指针
    // c++可通过new来实现
    // L.data = new int[InitList];
	L.data = (int*)malloc(InitSize * sizeof(int)) ;
	L.length = 0;
	L.MaxSize = InitSize;
}

2.3 删除顺序表

// 删除顺序表
void DestroyList(SeqList &L) {
    // 删除顺序表先释放内存,再将data置空、length设为0即可
    // 不能忘记使用free,使用malloc拓展的内存,如果不进行释放,就将指针指向了Null
    // 就会导致之后无法再释放那部分内存(指针指向已经改变),导致内存泄露
    if(L.data != NULL) {
        free(L.data);
        L.data = NULL;
        L.length = 0;
        L.MaxSize = 0;
    }
}

2.4 返回表长

// 返回表长
int Length(SeqList L) {
    // 直接返回length即可
    return L.length;
}

2.5 按值查找

// 按值查找
int LocateElem(SeqList L, int e) {
    for(int i = 0;i < L.length;i++) {
        if(L.data[i] == e) {
            // i为其在顺序表中的位置,i + 1为其位序
            return i + 1;
        }
    }
    // 返回-1表示未找到
    return -1;
}

2.5 按位查找

// 按位查找
int GetElem(SeqList L, int i) {
    //判断i的范围是否有效
    if(i < 1 || i > L.length) 
        return -1;

    // i为位序,即第i个元素
    return L.data[i - 1];
}

2.6 插入操作

在这里插入图片描述

// 顺序表插入操作
bool ListInsert(SeqList &L, int i, int e) {
    // 判断i是否有效
    // 此处之所以为i+1,是因为插入之后长度增加了1
    if(i < 1 || i > L.length + 1) {
        return false;
    }
    // 还需判断目前长度是否与最大容量值相等,是否需要进行空间扩充
    if(L.length >= L.MaxSize) {
        // 表已满,不能插入
        // return false;
        // 也可以选择扩充空间,此处扩充一个初始值空间
        int *p = (int *)malloc((L.MaxSize + InitSize) * sizeof(int));
        for(int i = 0;i < L.length;i++) {
            p[i] = L.data[i];
        }
        // 释放data所占用空间
        free(L.data);
        // 修改data指向并修改最大长度值
        L.data = p;
        L.MaxSize = L.MaxSize + InitSize;
    }
    // 插入操作
    // 先将第i个元素及之后元素后移
    for(int j = L.length;j >= i;j--) {
        L.data[j] = L.data[j - 1];
    }
    // 在位置i处插入e
    L.data[i - 1] = e;
    // 长度增加
    L.length++;
    return true;
}

2.7 删除操作

在这里插入图片描述

// 顺序表删除操作
// 此处e为引用变量的原因是e可在外部定义,而只有通过引用变量才能将值的变化保留下来
// 即在完成删除操作之后,外部的e值即会变为所删除的元素的值
bool ListDelete(SeqList &L, int i, int &e) {
    // 判断i是否有效
    if(i < 1 || i > L.length) {
        return false;
    }
    // e为即将删除的元素
    e = L.data[i - 1];
    // 删除操作
    // 将第i个元素之后的元素前移
    for(int j = i;j < L.length;j++) {
        L.data[j - 1] = L.data[j]; 
    }
    // 注意长度值的修改
    L.length--;
    return true;
}

2.8 判空操作

// 判空操作
bool Empty(SeqList L) {
    // 直接根据长度判断即可
    if(L.length == 0) {
        return true;
    }
    return false;
}

2.9 输出操作

// 顺序表的输出操作
bool PrintList(SeqList L) {
    // 若表为空,则不能输出
    if(Empty(L)) {
        return false;
    }
    // 循环遍历输出
    for(int i = 0;i < L.length;i++) {
        printf("data[%d]=%d\n", i, L.data[i]);
    }
    return true;
}

2.10 增加数组长度

// 增加数组长度
void IncreaseSize(SeqList &L, int len){
	int *p = L.data;
	L.data = (int *)malloc((L.MaxSize + len) * sizeof(int));
	for(int i = 0;i < L.length;i++){
        // 将数据复制到新区域
		L.data[i] = p[i];
	}
    // 顺序表最大容量增加len
	L.MaxSize = L.MaxSize + len;
    //释放原来的内存空间
	free(p);
} 

2.11全部代码

// 顺序表实现——动态分配
#include<stdio.h>
#include<stdlib.h>  // malloc、free函数

#define InitSize 10 // 定义初始长度

typedef struct {
    int* data;  // 指向动态分配顺序表的指针
    int MaxSize;    // 顺序表最大容量
    int length; // 顺序表当前长度
} SeqList;

// 初始化
void InitList(SeqList &L) {
    // 用malloc函数申请一片连续的存储空间
    // 注意:前面部分的强转不能忘记,否则会出错,应转成对应类型的指针
    // c++可通过new来实现
    // L.data = new int[InitList];
	L.data = (int*)malloc(InitSize * sizeof(int)) ;
	L.length = 0;
	L.MaxSize = InitSize;
}

// 删除顺序表
void DestroyList(SeqList &L) {
    // 删除顺序表先释放内存,再将data置空、length设为0即可
    // 不能忘记使用free,使用malloc拓展的内存,如果不进行释放,就将指针指向了Null
    // 就会导致之后无法再释放那部分内存(指针指向已经改变),导致内存泄露
    if(L.data != NULL) {
        free(L.data);
        L.data = NULL;
        L.length = 0;
        L.MaxSize = 0;
    }
}

// 返回表长
int Length(SeqList L) {
    // 直接返回length即可
    return L.length;
}

// 按值查找
int LocateElem(SeqList L, int e) {
    for(int i = 0;i < L.length;i++) {
        if(L.data[i] == e) {
            // i为其在顺序表中的位置,i + 1为其位序
            return i + 1;
        }
    }
    // 返回-1表示未找到
    return -1;
}

// 按位查找
int GetElem(SeqList L, int i) {
    //判断i的范围是否有效
    if(i < 1 || i > L.length) 
        return -1;

    // i为位序,即第i个元素
    return L.data[i - 1];
}

// 顺序表插入操作
bool ListInsert(SeqList &L, int i, int e) {
    // 判断i是否有效
    // 此处之所以为i+1,是因为插入之后长度增加了1
    if(i < 1 || i > L.length + 1) {
        return false;
    }
    // 还需判断目前长度是否与最大容量值相等,是否需要进行空间扩充
    if(L.length >= L.MaxSize) {
        // 表已满,不能插入
        // return false;
        // 也可以选择扩充空间,此处扩充一个初始值空间
        int *p = (int *)malloc((L.MaxSize + InitSize) * sizeof(int));
        for(int i = 0;i < L.length;i++) {
            p[i] = L.data[i];
        }
        // 释放data所占用空间
        free(L.data);
        // 修改data指向并修改最大长度值
        L.data = p;
        L.MaxSize = L.MaxSize + InitSize;
    }
    // 插入操作
    // 先将第i个元素及之后元素后移
    for(int j = L.length;j >= i;j--) {
        L.data[j] = L.data[j - 1];
    }
    // 在位置i处插入e
    L.data[i - 1] = e;
    // 长度增加
    L.length++;
    return true;
}

// 顺序表删除操作
// 此处e为引用变量的原因是e可在外部定义,而只有通过引用变量才能将值的变化保留下来
// 即在完成删除操作之后,外部的e值即会变为所删除的元素的值
bool ListDelete(SeqList &L, int i, int &e) {
    // 判断i是否有效
    if(i < 1 || i > L.length) {
        return false;
    }
    // e为即将删除的元素
    e = L.data[i - 1];
    // 删除操作
    // 将第i个元素之后的元素前移
    for(int j = i;j < L.length;j++) {
        L.data[j - 1] = L.data[j]; 
    }
    // 注意长度值的修改
    L.length--;
    return true;
}

// 判空操作
bool Empty(SeqList L) {
    // 直接根据长度判断即可
    if(L.length == 0) {
        return true;
    }
    return false;
}

// 顺序表的输出操作
bool PrintList(SeqList L) {
    // 若表为空,则不能输出
    if(Empty(L)) {
        return false;
    }
    // 循环遍历输出
    for(int i = 0;i < L.length;i++) {
        printf("data[%d]=%d\n", i, L.data[i]);
    }
    return true;
}

// 增加数组长度
void IncreaseSize(SeqList &L, int len){
	int *p = L.data;
	L.data = (int *)malloc((L.MaxSize + len) * sizeof(int));
	for(int i = 0;i < L.length;i++){
        // 将数据复制到新区域
		L.data[i] = p[i];
	}
    // 顺序表最大容量增加len
	L.MaxSize = L.MaxSize + len;
    //释放原来的内存空间
	free(p);
} 

int main() {
    SeqList L;
    // 初始化
    InitList(L);
    // 插入数据
    ListInsert(L, 1, 1);
    ListInsert(L, 2, 2);
    ListInsert(L, 1, 3);
    // 输出所有数据
    PrintList(L);
    // 输出表长
    printf("length=%d\n", Length(L));
    // 按值查找
    printf("locate=%d\n", LocateElem(L, 3));
    // 按位查找
    printf("index=%d\n", GetElem(L, 3));
    // 判空操作
    printf("empty=%d\n", Empty(L));
    // 删除数组数据
    int e;
    ListDelete(L, 3, e);
    PrintList(L);
    // 删除顺序表
    DestroyList(L);
    // 判空操作
    printf("empty=%d\n", Empty(L));
}

3.静态分配

静态分配即是一旦顺序表大小和空间确定,之后不可改变。

// 顺序表实现——静态分配
#include<stdio.h>
#define MaxSize 10  // 宏定义 表的最大长度

// 静态分配 数组的大小与空间固定,不可改变
typedef struct {
    int data[MaxSize];  // 顺序表元素
    int length; // 顺序表长度(当前!!!)
} StaticSeqList; // 顺序表类型定义

// 初始化
void InitList(StaticSeqList &L) {
    // 初始表内无元素,长度设为0
    L.length = 0;
    // 将顺序表所有值设为0,防止脏数据
    // 脏数据即是指:在内存被分配后,系统所分配的内存之前可能用于存储其他数据,即可能有残留
    // 如果将此部分删除,直接输出data,不会报错,但输出内容可能会存在问题
    for(int i = 0;i < MaxSize;i++) {
        L.data[i] = 0;
    }
}

int main() {
    StaticSeqList L;    // 声明一个顺序表
    InitList(L);    // 初始化
    // 输出data内容
    for(int i = 0;i < MaxSize;i++) {
        printf("data[%d]=%d\n", i, L.data[i]);
    }
    return 0;
}
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Silver Star

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值