1. 线性结构--线性表

线性表

定义

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

  • 表中元素个数称为线性表的长度
  • 线性表没有元素时,称为空表
  • 表起始位置称表头,表结束位置称表尾

抽象数据类型描述

  • 类型名称:线性表(List)
  • 数据对象集:线性表是 n(0) 个元素构成的有序序列 (a1,a2,...,an)
  • 操作集:线性表 LList ,整数 i 表示位置,元素 XElementType ,线性表的主要操作有:
    1. List MakeEmpty():初始化一个空线性表L
    2. ElementType FindKth(int K, List L):根据位序K,返回相应的元素
    3. int Find(ElementType X, List L):在线性表L中查找X第一次出现的位置
    4. void Insert(ElementType X, int i, ListL):在位序i前插入一个新元素X
    5. void Delete(int i, List L):删除指定位序i的元素
    6. int Length(List L):返回线性表L的长度n

顺序存储实现

利用数组的连续存储空间顺序存放线性表的个元素。

线性表的代码定义

typedef struct LNode *List;
struct LNode {
    ElementType Data[MAXSIZE];
    int Last;
};
struct LNode L;
List Ptrl;
  • 访问下标为i的元素:L.Data[[i]Ptrl->Data[i]
  • 线性表的长度:L.Last + 1Ptrl->Last + 1

主要操作的实现

初始化(建立空的顺序表)
List MakeEmpty() {
    List PtrL;
    PtrL = (List)malloc(sizeof(struct LNode));
    PtrL-Last = -1;
    return PtrL;
}
查找
int Find(ElementType X, List PtrL) {
    int i = 0;
    while (i <= PtrL->Last && PtrL->Data[i] != X)
        i++;

    if (i > PtrL->Last) // 说明没有找到,返回-1
        return -1;
    return i;           // 找到后返回的是存储位置
}

查找成功的平均比较次数为 (n+1)/2 ,平均时间性能为 O(n)

插入

在第 i(iin+1) 个位置插入一个值为X的新元素
image

void Insert(ElementType X, int i, List PtrL) {
    int j;
    if (PtrL->Last == MAXSIZE - 1) {    // 表空间已满,不能插入
        printf("表满");
        return;
    }

    if (i < 1 || i > PtrL->Last + 2) { // 位置只能从第一个到末尾之间
        printf("位置不合法");
        return;
    }

    for (j = PtrL->Last; j >= i - 1; j--)   // 将ai ~ an倒序向后移动
        PtrL->Data[j + 1] = PtrL->Data[j] ; 

    PtrL->Data[i - 1] = X;                  // 新元素插入
    PtrL->Last++;                           // Last仍然指代最后元素的下标
}

元素的向后移动:
* 平均移动次数为 n/2
* 平均时间性能为 O(n)

删除

删除表的第 i(1in) 个位置的元素
image

void Delete(int i, List PtrL) {
    int j;
    if (i < 1 || i > PtrL->Last + 1) {
        printf("不存在第%d个元素", i);
        return;
    }

    for (j = i; j <= PtrL->Last; j++)
        PtrL->Data[j - 1] = PtrL->Data[j];  // 将ai+1 ~ an 顺序向前移动
    PtrL->Last--;                           // Last仍然指代最后元素的下标
}

链式存储实现

不要求逻辑上相邻的两个元素物理上也相邻。通过“链”建立起数据元素之间的逻辑关系。

线性表的代码定义

typeof struct LNode *List;
struct LNode {
    ElementType Data;
    List Next;
};
struct LNode L;
List PtrL;

主要操作的实现

求表长
int Length(List PtrL) {
    List p = PtrL;      // p指向表的第一个结点
    int len = 0;
    while (p != NULL) {
        p = p->Next;
        len++;          // 当前P指向的是第len个结点
    }

    return len;
}

时间性能为 O(n)

查找
按序号查:FindKth
List FindKth(int K, List PtrL) {
    List p = PtrL;
    int i = 1;
    while (p != NULL && i < k) {
        p = p->Next;
        i++;
    }

    if (i == k)             // 说明找到第K个元素
        return P;

    return NULL;
}

平均时间性能为 O(n)

按值查找:Find
List Find(ElementType X, List PtrL) {
    List p = PtrL;
    while (p != NULL && p->Data != X)   // 如果在链表中没有元素等于X,那么会返回NULL
        p = p->Next;

    return p;
}

平均时间性能为 O(n)

插入

在第 i1(1in+1) 个结点后插入一个值为X的新结点:
1. 先构造一个新结点,用s指向
2. 再找到链表的第 i1 个结点,用p指向
3. 然后修改指针,插入结点(p之后插入新结点是S)
image

// 不带头结点的链表
List Insert(ElementType X, int i, List PtrL) {
    List p, s;

    if (i == 1) {                               // 新结点插入在表头
        s = (List)malloc(sizeof(struct LNode)); // 创建一个新结点
        s->Data = x;
        s->Next = PtrL;
        return s;
    }

    p = FindKth(i - 1, PtrL);   // 查找到第i-1个结点
    if (p == NULL) {            // 第i-1个不存在,不能插入
        printf("参数i错误");
        return NULL;
    }

    s = (List)malloc(sizeof(struct LNode)); // 创建一个新结点
    s->Data = x;
    s->Next = p->Next;                      // 新结点插入在第i-1个结点后面
    p->Next = s;
    return PtrL;
}

平均查找次数为 n/2 ,平均时间性能为 O(n)

删除

删除链表的第 i(1in) 个位置的结点:
1. 先找到链表的第 i1 个结点,用p指向
2. 再用指针s指向要被删除的结点(p的下一个结点)
3. 然后修改指针,删除s所指结点
4. 最后释放s所指结点的空间

image

List Delete(int i, List PtrL) {
    List p, s;
    if (i == 1) {                   // 如果删除的是表的第一个结点
        s = PtrL;                   // s指向第一个结点
        if (PtrL != NULL)           // 从链表中删除
            PtrL = PtrL->Next;
        else 
            return NULL;
        free(s);
        return PtrL;
    }

    p = FindKth(i - 1, PtrL);       // 查找第i-1个结点
    if (P == NULL || p->Next == NULL) {
        printf("第%d个结点不存在", i - 1);
        return NULL;
    }

    s = p->Next;                    // s指向第i个结点
    p->Next = s->Next;              // 从链表中删除
    free(s);                        // 释放被删除的结点
    return PtrL;
}

平均查找次数为 n/2 ,平均时间性能为 O(n)

广义表(Generalized List)

  • 广义表是线性表的推广
  • 对于线性表而言,n个元素都是基本的单元素
  • 广义表中,这些元素不仅可以是单元素也可以是另一个广义表

代码定义

typedef struct GNode *GList;
struct GNode {
    int Tag;                // 标志域:0表示结点是单元素,1表示结点是广义表
    union {                 // 子表指针域Sublist与单元素数据域Data复用,即共用存储空间
        ElementType Data;
        GList SubList;
    } URegion;
    GList Next;             // 指向后继结点
};

多重链表

链表中的结点可能同时隶属于多个链。

  • 多重链表中结点的指针域会有多个,如前面例子包含了Next和SubList两个指针域
  • 但包含两个指针域的链表并不一定是多重链表,比如双向链表不是多重链表

多重链表有广泛的的用途:基本上如树、图这样相对复杂的数据结构都可以采用多重链表方式实现存储。

多重链表存储矩阵

image

采用一种典型的多重链表——十字链表来存储稀疏矩阵:
* 只存储矩阵非0元素项,结点的数据域:行坐标Row、列坐标Col、数值Value
* 每个结点通过两个指针域,把同行、同列串起来:
* 行指针(或称为向右指针)Right
* 列指针(或称为向下指针)Down

image

  • 用一个标识域Tag来区分头结点与非0元素结点
  • 头结点的标识域为”Head”,矩阵非0元素结点的标识值为”Term”
    image
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值