数据结构-线性表

1. 定义

线性表是由同一类型的数据元素构成的有序序列的线性结构。

2.实现

2.1 顺序存储:在内存中用地址连续的一块存储空间顺序存放线性表中的各个元素,用一维数组表示顺序存储的数据区域。

MAXSIZE: 定义的数组的容量,线性表中数据从Data[0]开始存放。
Last : 记录线性表中最后一个元素的位置(数组下标)。表空时Last = -1。
struct LNode: 为了体现数据组织的整体性,将数组Data和Last封装成结构作为顺序表的类型。
typedef PtrToLNode List:由此,可以利用List定义线性表 List L;通过L可以访问相应内容 L->Data[i] , L ->Last

#define MAXSIZE 10
#define ERROR -1
// 线性表的顺序存储

typedef int ElementType;// Data数组中存放数据的类型
typedef int Position;
typedef struct LNode *PtrToLNode;
typedef PtrToLNode List; // List 定义为结构体指针

struct LNode {
    ElementType Data[MAXSIZE];
    Position Last;
};

基本操作:

  1. List MakeEmpty() : 初始化线性表
  2. void PrintData(List L) : 打印线性表Data中存储的所有内容
  3. bool Insert(List L,ElementType X, int i): 插入元素,i为制定位序
  4. bool Delete(List L,int i): 删除元素,i为指定位序
  5. Position Find(List L, ElementType X): 查找元素
  6. int Length:返回线性表长度

完整代码

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

#define MAXSIZE 10
#define ERROR -1
// 线性表的顺序存储

typedef int ElementType;// Data数组中存放数据的类型
typedef int Position;
typedef struct LNode *PtrToLNode;
typedef PtrToLNode List; // List 定义为结构体指针

// 将数组Data和变量Last分装成一个结构体
struct LNode {
    ElementType Data[MAXSIZE];
    Position Last;
};

// 初始化线性表
List MakeEmpty() {
    List L; // 利用List定义线性表L,构建一个空表
    L = (List) malloc(sizeof(struct LNode)); // 动态分配表结构所需要的存储空间
    L->Last = -1; // 将表中Last指针置-1
    return L;    // 返回结构体指针
}

// 打印线性表中的数据
void PrintData(List L) {
    int i = 0;
    if(L->Last==-1) printf("表为空");
    while (i < L->Last + 1) {
        printf("%d ", L->Data[i]);
        i++;
    }
    printf("\n");
}

// 插入元素: 在L的制定位序i前插入一个新元素X,成功返回true,失败返回false(位序i元素的数组下标为i-1)
bool Insert(List L, ElementType X, int i) {
    // 先判断插入是否合法 1) 表空间是否已满 2)插入位序的合法性
    if (L->Last == MAXSIZE - 1 || i < 1 || i > L->Last + 2) {
        printf("插入失败\n");
        return false;
    }
    // i-1后的数都往后挪一位
    else{
        for (int j = L->Last; j >= i - 1; j--)
            L->Data[j + 1] = L->Data[j];
        L->Data[i - 1] = X;
        L->Last++;
        return true;
    }
}


// 删除元素: 给定位序i 删除数组中的i-1
bool Delete(List L,int i){
    // 先判断删除合法性
    if(i<1||i>L->Last){
        printf("表中不存在位序为 %d 的元素,删除失败",i);
        return false;
    }
    // 删除元素
    else{
        for(int j = i-1;j<=L->Last;j++)
            L->Data[j-1] = L->Data[j];
        L->Last --;
        return true;
    }
}

// 查找元素: 查找和X相等的元素, 返回数组下标
Position Find(List L, ElementType X){
    Position i = 0;
    while(i<=L->Last){
        if(L->Data[i] == X) return i;
        i++;
    }
    return ERROR;
}

// 返回列表长度
int Length(List L){
    return L->Last+1;
}


int main() {
    int findResult;
    int len;
    List list;

    list = MakeEmpty();

    Insert(list, 10, 1);
    Insert(list, 20, 2);
    Insert(list, 30, 3);
    Insert(list, 40, 4);
    Insert(list, 50, 5);
    PrintData(list);

    findResult = Find(list,30);
    printf("%d\n",findResult);
    Delete(list,1);
    PrintData(list);

    len = Length(list);
    printf("%d\n",len);


}

2.2 链式存储:与顺序存储相比,它不需要用地址连续的存储单元来实现,通过一个指针来连接各个分散的结点形成链状结构。每个结点存放一个元素以及指向下一节点的指针。链表可分为带头结点的链表和不带头结点的链表。

完整代码(带头节点的链表)

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

#define ERROR -1


typedef int ElementType;// Data数组中存放数据的类型
typedef struct LNode *PtrToLNode;
typedef PtrToLNode Position; // 这里的位置是结点的地址
typedef PtrToLNode List; // List 定义为结构体指针


// 将数组Data和变量Last分装成一个结构体
struct LNode {
    ElementType Data; // 保存当前元素
    PtrToLNode Next; // 指向下一个结点的指针
};


List MakeEmpty() {
    List L; // 利用List定义线性表L,构建一个空表
    L = (List) malloc(sizeof(struct LNode)); // 动态分配表结构所需要的存储空间
    L->Next = NULL; // 将表中Last指针置-1
    return L;    // 返回结构体指针
}

// 插入数据
bool Insert(List L, ElementType X, int index) {
    Position tmp, pre;
    int cnt = 0;

    pre = L; // pre指向表头
    while (pre && cnt < index - 1) {
        pre = pre->Next;
        cnt++;
    }
    if (pre == NULL || cnt != index - 1) {
        printf("插入位置错误\n");
        return ERROR;
    } else {
        tmp = (Position) malloc(sizeof(struct LNode));
        tmp->Data = X;
        tmp->Next = pre->Next;
        pre->Next = tmp;
        return true;
    }
}

// 删除数据
bool Delete(List L, int index) {
    Position tmp, pre;
    int cnt = 0;

    pre = L; // pre指向表头

    // 查找位序为index-1的结点
    while (pre && cnt < index - 1) {
        pre = pre->Next;
        cnt++;
    }
    if (pre == NULL || cnt != index - 1) {
        printf("删除位置错误\n");
        return ERROR;
    } else {
        tmp = pre->Next;
        pre->Next = tmp->Next;
        free(tmp);
        return true;
    }
}

// 返回线性表的长度
int Length(List L) {
    int cnt = 0;
    while (L) {
        L = L->Next;
        cnt++;
    }
    return cnt;
}

// 打印线性表中的数据
void PrintData(List L) {
    // 表头不放数据, 跳过表头读取
    while (L->Next) {
        L = L->Next;
        printf("%d", L->Data);
    }
    printf("\n");
}



int main() {
    List list;
    list = MakeEmpty();
    printf("线性表长度为 %d \n", Length(list));

    Insert(list, 1, 1);
    PrintData(list);
    Insert(list, 2, 2);
    PrintData(list);
    Insert(list, 4, 3);
    PrintData(list);
    printf("线性表长度为 %d \n", Length(list));

    Delete(list, 1);
    PrintData(list);
    printf("线性表长度为 %d \n", Length(list));
}

3 顺序表 vs 链表

  1. 链表在随机访问元素时需要通过遍历来完成,而顺序表利用数组特性直接访问得到
  2. 顺序表在插入元素时需要移动后续所有元素,而链表只需要修改结点指向即可完成插入

总结: 当读取数据多于插入删除数据时,用顺序表;当插入删除数据多于读取时,用链表。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值