线性表


线性表是一种最简答的线性结构。线性表的主要操作特定是可以再任意位置插入和删除数据元素。

线性表可以用顺序存储结构和链式存储结构存储。用顺序存储结构实现的线性表称作顺序表,用链式存储结构实现的线性表称作链表。链表主要有单列表、循环列表双向循环列表

线性表定义

线性结构的特定是,除第一个和最后一个数据元素外,每个数据元素只有一个前驱数据元素和一个后继数据元素。线性表是一种可以在任意位置进行插入和删除元素操作的。线性表是一种最简单的线性结构。

顺序表

顺序存储结构的线性表称为顺序表,用 C 语言实现顺序存储结构的方法是数组。

数组有静态数组和动态数组两种。静态数组存储空间的申请和释放由系统自动完成,动态数组存储空间的申请和释放由用户通过调用系统函数自己完成。

使用静态数组实现顺序表(时间复杂度 O(n)):

#define MaxSize 100
typedef int DataType;

typedef struct SeqList
{
    DataType list[MaxSize];
    int size;
}List;

// 初始化
void listInit(List *l)
{
    l->size = 0;
}

// 返回顺序表大小
int size(List l)
{
    return l.size;
}

// 在顺序表的 index 位置插入数据元素 item
int insert(List *l, int index, DataType item)
{
    int j = 0;

    if (l->size >= MaxSize)
    {
        return 1;
    }
    else if (0 > index || index > l->size)
    {
        return 1;
    }
    else 
    {
        for (j = l->size; j > index; j--)
        {
            l->list[j] = l->list[j-1];
        }
        
        l->list[index] = item;
        l->size++;

        return 0;
    }
}

// 在顺序表的 index 位置删除数据元素
int delete(List *l, int index, DataType *item)
{
    int j = 0;

    if (0 >= l->size)
    {
        return 1;
    }
    else if (0 > index || index > l->size-1)
    {
        return 1;
    }
    else 
    {
        *item = l->list[index];
        for (j = index+1; j <= l->size-1; j++)
        {
            l->list[j-1] = l->list[j];
        }
        
        l->size--;
        return 0;
    }
}

// 返回在顺序表的 index 位置的元素
int peek(List l, int index, DataType *item)
{
    if (0 > index || index > l.size-1)
    {
        return 1;
    }
    else 
    {
        *item = l.list[index];
        return 0;
    }
}

链表

链式存储结构的线性表称为链表。

链表主要有单链表、单循环链表和双循环链表三种。

单链表中,构成列表的节点只有一个指向直接后继节点的指针域。若设计的单链表带头节点,则无论是在第一个数据元素节点前插入还是在其它数据元素点前插入,都不会改变头指针的值;若设计的单链表不带头节点,则在第一个数据元素节点前插入和在其他数据元素节点前插入算法的处理方法不同。类似地,若设计的单链表带头节点,则删除第一个元素节点和删除其他数据节点算法的处理方法相同;设计的单链表不带头节点,则删除第一个数据元素节点和删除其他数据元素节点的算法的处理方法不相同。因此,单列表一般构造带头节点的单链表。

单循环链表是单链表的另一种形式,其结构特点是链表中最后一个节点的指针域不在是结束标记,而是指向整个列表的第一个节点,从而使列表形成一个环。带头节点的单循环列表更为常用。

双向链表中,每个节点除后继指针域外还有一个前驱指针域。带头节点的双向链表更为常用。双向链表也分为循环和非循环两种结构,循环双向链表更为常用。

C 语言实现单链表:

typedef int DataType;

typedef struct SLNode
{
    DataType data;
    struct SLNode *next;
}Node;

void listInit(Node **head)
{
    *head = (Node*)malloc(sizeof(Node));
    (*head)->next = NULL;
}

int listLength(Node *head)
{
    Node *p = head;
    int size = 0;
    while (NULL != p->next)
    {
        p = p->next;
        size++;
    }
    
    return size;
}

int listInsert(Node *head, int index, DataType item)
{
    Node *p, *q;
    int j = -1;

    p = head;

    while (NULL != p->next && j < index -1)
    {
        p = p->next;
        j++;
    }

    if (j != index - 1)
    {
        return 1;
    }
    
    q = (Node*)malloc(sizeof(Node));
    q->data = item;
    q->next = p->next;
    p->next = q;

    return 0;
}

int listDelete(Node *head, int index, DataType *item)
{
    Node *p, *s;
    int j = -1;

    p = head;

    while (NULL != p->next && NULL != p->next->next && j < index -1)
    {
        p = p->next;
        j++;
    }
    
    if (j != index -1)
    {
        return 1;
    }
    
    s = p->next;
    *item = s->data;
    p->next = p->next->next;
    free(s);

    return 0;
}

int listGet(Node *head, int index, DataType *item)
{
    Node *p = head;
    int j = -1;

    while (NULL != p->next && j < index)
    {
        p = p->next;
        j++;
    }
    
    if (j != index)
    {
        return 1;
    }
    
    *item = p->data;

    return 0;
}

int listDestroy(Node **head)
{
    Node *p = NULL;
    Node *q = NULL;

    p = *head;
    while (p != NULL)
    {
        q = p;
        p = p->next;
        free(q);
    }
    
    *head = NULL;
}

C 语言实现循环双向链表:

typedef int DataType;

typedef struct DLNoode
{
    DataType data;
    struct DLNoode *next;
    struct DLNoode *prior;
}Node;

void listInit(Node **head)
{
    *head = (Node*)malloc(sizeof(Node));
    (*head)->prior = *head;
    (*head)->next = *head;
}

int listInsert(Node *head, int index, DataType item)
{
    Node *s = NULL;
    Node *p = head->next;
    int j = 0;

    while (p != head && j < index)
    {
        p = p->next;
        j++;
    }
    
    if (j != index)
    {
        return 1;
    }
    
    s = (Node*)malloc(sizeof(Node));
    s->data = item;
    s->prior = p->prior;
    (p->prior)->next = s;
    s->next = p;
    p->prior = s;

    return 0;
}

int listDelete(Node *head, int index, DataType *item)
{
    Node *p;
    int j;

    p = head->next;
    j = 0;

    while (p->next != head && j < index)
    {
        p = p->next;
        j++;
    }
    
    if (j != index)
    {
        return 1;
    }

    *item = p->data;
    p->prior->next = p->next;
    p->next->prior = p->prior;
    free(p);

    return 0;
}

int listLength(Node *head)
{
    Node *p = head;
    int size = 0;

    while (p->next != head)
    {
        p = p->next;
        size++;
    }
    
    return size;
}

void listDestroy(Node **head)
{
    Node *p, *q;
    int i, n= listLength(*head);

    p = *head;
    for (int i = 0; i < n; i++)
    {
        q = p;
        p = p->next;
        free(q);
    }
    
    *head = NULL;
}

void listErgodic(Node *head)
{
    Node *p = head->next;
    while (p != head)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");

    p = p->prior;
    while (p != head)
    {
        printf("%d ", p->data);
        p = p->prior;
    }

    printf("\n");
}

静态链表

在链式存储的结构中,实现数据元素直接的次序关系依靠指针。也可以用数组来构造链表,方法是:在数组中增加一个(或两个)指针域,这些指针域用来存放下一个(或上一个)数据元素在数组中的下标,从而构成用数组构造的单链表(或双向链表)。由于相对于申请节点的内存空间的动态性来说,数组内存空间的申请方式是静态的,所以这种存储结构称作静态链表

由于静态链表中增加的指针仿真了链式存储结构中的指针,所以静态列表中的指针也称为仿真指针

静态链表不仅可以存储线性结构,也可以存储如树、二叉树、图等非线性结构。

静态链表存储非线性结构时,通常需要一个以上的仿真指针。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

二流人物

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

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

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

打赏作者

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

抵扣说明:

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

余额充值