编写顺序表的插入和删除算法_数据结构与算法之线性表-顺序表实现(C语言版本)...

f66f8e6e133f6832743aa25bddcfbd80.png
原文托管在Github: https:// github.com/shellhub/blo g/issues/52

数据结构与算法之线性表-顺序表实现(C语言版本)

前言

数据结构与算法是一个程序员必备的技能之一,而顺序表更是每个程序员在面试过程中要经常被问到的,如Java语言中的ArrayList类的底层实现就是使用顺序表实现的,别把顺序表想的有多么高大上,其实就是使用数组实现的一种线性表

什么是线性表

线性表(英语:Linear List)是由n(n≥0)个数据元素(结点)a[0],a[1],a[2]…,a[n-1]组成的有限序列。 其中: 数据元素的个数n定义为表的长度 = "list".length() ("list".length() = 0(表里没有一个元素)时称为空表) 将非空的线性表(n>=1)记作:(a[0],a[1],a[2],…,a[n-1]) * 数据元素a[i](0≤i≤n-1)只是个抽象符号,其具体含义在不同情况下可以不同

一个数据元素可以由若干个数据项组成。数据元素称为记录,含有大量记录的线性表又称为文件。这种结构具有下列特点:存在一个唯一的没有前驱的(头)数据元素;存在一个唯一的没有后继的(尾)数据元素;此外,每一个数据元素均有一个直接前驱和一个直接后继数据元素。

什么是顺序表

顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构。

顺序表的实现

为了能实现顺序表的基本操作如(增,删,改,查),我们使用结构体封装一个指向一维数组的指针base,同时提供一个名字叫做length的整型变量表示顺序表中实际有用的元素个数,当插入一个元素时length++, 当删除一个元素时length--,所以length可以记录当前顺序表的长度

顺序表综合案列-学生信息管理系统

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>

#define INIT_SIZE 1
#define INCREMENT_SIZE 5
typedef struct {
    int id; //学号
    int age; //年龄
    char name[10]; //姓名
} Student;

typedef Student ElemType;

typedef struct {
    ElemType *base;
    int size; /* 顺序表的最大容量 */
    int length; /* 记录顺序表的元素个数 */
} SqList;

/**
 * 初始化顺序表
 * @param p 指向顺序表的指针
 * @return 如果初始化成功返回true否则返回false
 */
bool init(SqList *p) {
    p->base = malloc(sizeof(SqList) * INIT_SIZE);
    if (p->base == NULL) {
        return false;
    }
    p->size = INIT_SIZE;
    p->length = 0;
    return true;
}

/**
 * 指定位置插入数据元素
 * @param p 指向顺序表的指针
 * @param index 插入的下标
 * @param elem 插入的元素值
 * @return 如果插入成功返回true,否则返回false
 */
bool insert(SqList *p, int index, ElemType elem) {
    if (index < 0 || index > p->length) {
        perror("插入下标不合法");
        return false;
    }

    //如果顺序表满了,则重新分配更大的容量
    if (p->length == p->size) {
        int newSize = p->size + INCREMENT_SIZE;
        ElemType *newBase = realloc(p->base, newSize);
        if (newBase == NULL) {
            perror("顺序表已满,重新分配内存失败");
            return false;
        }
        p->base = newBase;
        p->size = newSize;
    }

    //从最后一个元素开始依次把元素复制到后面的位置
    for (int i = p->length - 1; i >= index; --i) {
        p->base[i + 1] = p->base[i];
    }
    p->base[index] = elem;
    p->length++;
    return true;
}

/**
 * 删除指定下标的数据元素
 * @param p 指向顺序表的指针
 * @param index 删除的元素的下标
 * @param elem 返回删除的元素
 * @return 如果删除成功返回true否则返回false
 */
bool del(SqList *p, int index, ElemType *elem) {
    if (p->length == 0) {
        perror("顺序是空的,无法执行删除操作");
        return false;
    }
    if (index < 0 || index > p->length - 1) {
        perror("删除位置不合法");
        return false;
    }

    //把删除的元素保存起来
    *elem = p->base[index];
    //从删除位置开始依次把后面的元素赋值到前面
    for (int i = index; i < p->length - 1; ++i) {
        p->base[i] = p->base[i + 1];
    }
    p->length--;
    return true;
}

/**
 * 更新顺序表中特定的元素值
 * @param p 指向顺序表的指针
 * @param index 更新下标
 * @param elem 更改后的新元素值
 * @return 如果更改成功则返回true,否则返回false
 */
bool update(SqList *p, int index, ElemType elem) {
    if (p->length == 0) {
        perror("顺序表是空的,无法指向更新");
        return false;
    }

    if (index < 0 || index > p->length - 1) {
        perror("更新下标不合法");
        return false;
    }

    p->base[index] = elem;
    return true;
}

/**
 * 搜索顺序表中特定下标的元素
 * @param list 指定的顺序表
 * @param index 搜索的下标
 * @param elem 保存搜索到的元素
 * @return 如果搜索成功则返回true,否则返回false
 */
bool search(SqList list, int index, ElemType *elem) {
    if (list.length == 0) {
        perror("顺序表没有任何元素,无法查找");
        return 0;
    }

    if (index < 0 || index > list.length - 1) {
        perror("查找下标不合法");
        return false;
    }

    *elem = list.base[index - 1];
    return true;
}

/**
 * 打印顺序表
 * @param list 指定顺序表
 */
void output(SqList list) {
    printf("学号t年龄t姓名n");
    for (int i = 0; i < list.length; ++i) {
        printf("%dt%dt%sn", list.base[i].id, list.base[i].age, list.base[i].name);
    }
    printf("n");
}

int main() {
    SqList list;
    while (1) {
        printf("tt顺序表的基本操作n");
        printf("tt1.初始化顺序表n");
        printf("tt2.顺序表的插入n");
        printf("tt3.顺序表的删除n");
        printf("tt4.顺序表的查找(下标)n");
        printf("tt5.顺序表的修改n");
        printf("tt6.打印n");
        printf("tt0.退出n");

        int choice;
        printf("请输入功能编号:");
        scanf("%d", &choice);

        switch (choice) {
            case 1:
                if (init(&list)) {
                    printf("初始化成功n");
                }
                assert(list.length == 0);
                break;
            case 2:;
                ElemType elem;
                printf("请输入插入的学生学号:");
                scanf("%d", &elem.id);
                printf("请输入插入的学生年龄:");
                scanf("%d", &elem.age);
                printf("请输入插入的学生姓名:");
                scanf("%s", elem.name);

                printf("请输入插入位置:");
                int index;
                scanf("%d", &index);

                if (insert(&list, index, elem)) {
                    printf("插入成功n");
                }
                break;
            case 3:
                printf("请输入删除位置:");
                scanf("%d", &index);
                if (del(&list, index, &elem)) {
                    printf("删除的学生 学号:%dt年龄:%dt姓名:%sn", elem.id, elem.age, elem.name);
                }
                break;
            case 4:
                printf("请输入要查找的位置:");
                scanf("%d", &index);
                if (search(list, index, &elem)) {
                    printf("查找的学生 学号:%dt年龄:%dt姓名:%sn", elem.id, elem.age, elem.name);
                }
                break;
            case 5:
                printf("请输入更新位置:");
                scanf("%d", &index);

                printf("请输入更新后的学生学号:");
                scanf("%d", &elem.id);
                printf("请输入更新后的学生年龄:");
                scanf("%d", &elem.age);
                printf("请输入更新后的学生姓名:");
                scanf("%s", elem.name);
                if (update(&list, index, elem)) {
                    printf("更新成功n");
                }
                break;
            case 6:
                output(list);
                break;
            case 0:
                exit(0);
            default:
                printf("输入编号有误,请重新输入n");
                break;
        }
    }
    return 0;
}

顺序表优缺点

  • 优点
    • 因为顺序表使用数组实现,可以通过下标存取,所以存取速度极快,T(n)=O(1)
    • 无需为表中元素之间的逻辑关系而增加额外的存储空间
    • 空间利用效率高
  • 缺点
    • 插入删除均需要循环移动元素,比较浪费时间 T(n)=O(n)
    • 需要提前预估顺序表的长度(INIT_SIZE),分配太大浪费,造成内存的碎片化
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值