美文网首页
数据结构梳理 — 线性表

数据结构梳理 — 线性表

作者: 11e17ad00a2a | 来源:发表于2017-11-06 20:22 被阅读13次

线性表:由 >=0 个数据元素组成的有限序列(线性表有两种存储结构:顺序存储结构和链式存储结构)

一. 顺序存储结构的线性表

  • 图示:


    顺序表.png
  • 地址计算方法:
    如:已知数组int a[n]的初始地址是location(a[0]),求第i个元素的地址location(a[i])
location(a[i]) = location(a[0]) + (i-1)

因此,顺序存储结构的线性表 查询操作的时间复杂度为 O(1)

为了描述顺序表表,我们首先要声明一个结构,如下

/**
 首先声明一个顺序表的结构
 */
#define LIST_INIT_SIZE 10 //线性表存储空间的初始分配量
#define LISTINCREMENT 5   //线性表存储空间的分配增量(当存储空间不够时要用到)
typedef int ElemType;      //数据元素的类型,假设是int型的
typedef struct{
    ElemType *elem;       //存储空间的基地址
    int length;      //当前线性表的长度
    int listsize;    //当前分配的存储容量
}SqList;

1.创建线性表

/**
 
 创建线性表
 
 */
int InitList(SqList *L)
{
    L->elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));//开辟一个存储空间,并把这块存储空间的基地址赋值给elem
    if (L->elem == NULL)
    {
        return -1;//空间分配失败
    }
    
    L->length = 0;//线性表的当前长度
    L->listsize = LIST_INIT_SIZE;//当前分配量
    
    return 0;
}

2.1查找元素(按位置 or 地址查找),时间复杂度为O(1)

/**
 
 查找元素(按位置 or 地址查找),时间复杂度为O(1)
 查找第i个元素,存储在e中
 成功为0,失败为-1
 
 */
int GetElem(SqList *L, int i, ElemType *e)
{
    
#if 0  //按位置查找
    //判断查找的合法性
    if (i<1 || i>L->length)
    {
        return -1;
    }
    
    *e = L->elem[i-1];
    
    return 0;
#endif
    
    //按地址查找
    
    //判断查找的合法性
    if (i<1 || i>L->length)
    {
        return -1;
    }
    
    *e = *(L->elem+(i-1));
    return 0;
}

2.2查找元素(按值查找),时间复杂度为O(n)

/**
 
 查找元素(按值查找),时间复杂度为O(n)
 返回元素的坐标
 
 */
int LocateElem(SqList *L, ElemType x)
{
    int pos = -1;
    for (int i = 0; i < L->length; i++)
    {
        if (L->elem[i] == x)
        {
            pos = i;
        }
    }
    
    return pos;
}

3.插入元素,时间复杂度为O(n)

/**
 
 插入元素,时间复杂度为O(n)
 返回该坐标的元素
 
 */

int ListInsert(SqList *L, int i, ElemType e)
{
    //判断插入位置的合法性
    if (i<1 || i>L->length+1) return -1;
    //判断存储空间是否够用
    if (L->length >= L->listsize)
    {
        ElemType *newbase = (ElemType *)realloc(L->elem, (L->listsize + LISTINCREMENT)*sizeof(ElemType));
        if (!newbase) return -1;//存储空间分配失败
        L->elem = newbase;//新基址
        L->listsize += LISTINCREMENT;//增加存储容量
    }
    //插入操作
    ElemType *q, *p; //定义2个指针变量
    q = &(L->elem[i-1]); //q为插入位置(注意形参i是序号,序号是从从1开始的,而下标是从0开始的,因此这里转成下标后是i-1)
    for (p = &(L->elem[L->length - 1]); p >= q; --p) //从ai到an-1依次后移,注意后移操作要从后往前进行
    {
        *(p + 1) = *p;
    }
    *q = e;
    ++L->length;//表长加1
    return 0;
}

4.删除元素,时间复杂度为O(n)

/**
 
 删除元素,时间复杂度为O(n)
 删除第i个元素,并将删除的元素保存在e中
 */
int ListDelete(SqList *L, int i, ElemType *e)
{
    //判断删除位置是否越界
    if (i<1 || i>L->length)
    {
        return -1;
    }
    
    ElemType *p = &(L->elem[i]);//将p指向i位置的元素
    *e = *p;//将p指向i位置的元素保存在e中
    ElemType *q = &(L->elem[L->length-1]);//将q指向最后的元素
    for (; p <= q; p++)
    {
        *p = *(p+1);//将顺序表中的元素依次平移一个位置
    }
    
    return 0;
}

5.清空顺序表

/**
 
 清空顺序表
 */
int ListClean(SqList *L)
{
    L->length = 0;//把当前线性表的长度设置为0,表示清空
    return 0;
}

测试代码如下:

int main(int argc, const char * argv[]) {
    
    SqList *l = (SqList *)malloc(sizeof(SqList));
    
    //创建顺序表
    InitList(l);
    

    //从第1个元素开始,先顺序插入10个元素
    for (int i=1; i<11; i++)
    {
        ListInsert(l, i, 11-i);
    }
    
    //输出线性表
    for (int i = 0; i < 10; i++)
    {
        printf("%d ", l->elem[i]);
    }
    printf("\n");
    
    //在坐标为3的位置插入元素
    int status = ListInsert(l, 3, 99);
    
    //输出线性表
    for (int i = 0; i < l->length; i++)
    {
        printf("%d ", l->elem[i]);
    }
    printf("\n");
    
        
    //在顺序表中查找元素为7的坐标
    int pos = LocateElem(l, 7);
    printf("l->elem[%d] = %d", pos, l->elem[pos]);
    
    //删除第5个元素,并且删除的元素保存在e中
    ElemType e = 0;
    ListDelete(l, 5, &e);
    printf("\n");

    
    //输出线性表
    for (int i = 0; i < l->length; i++)
    {
        printf("%d ", l->elem[i]);
    }
    printf("\n");
    
    //查找第3个元素,并且结果保存在find_e中
    ElemType find_e = 0;
    GetElem(l, 3, &find_e);
    printf("find_e = %d ", find_e);
    printf("\n");

    
    
    if (l != NULL)
    {
        //清空顺序表
        ListClean(l);
        
        free(l->elem);
        free(l);
        l = NULL;
    }
        
    return 0;
}

二. 链式存储结构的线性表

解释俩概念头指针头节点

头指针:指向链表的第一个节点的指针,若链表有头节点,则是只想头节点的指针。头指针的变量名字常用来表识链表的名字。无论链表是否为空,头指针均不为空。(是链表的必要元素)
头节点:头节点是为了从左统一和方便而设立的,放在第一个元素的节点之前,其数据域一般无意义(但也可以用来存放链表的长度)。

单链表

单链表、空链表图例:


单链表.png

为了描述单链表,我们首先要声明一个结构,如下

/**
 首先声明一个单链表的结构
 */

typedef int ElemType;      //数据元素的类型,假设是int型的

typedef struct{
    ElemType data;//数据域
    struct LNode *next;//指针域
    
}LNode;

typedef LNode LinkList;

1.创建单链表
头插法

/**
 
 1.1创建链表(头插法) 时间复杂度O(n)
 
 */
LinkList * CreateListHead(int n)
{
    LNode *L = NULL;
    L = (LNode *)malloc(sizeof(LNode));
    L->next = NULL;
    
    LNode *p = NULL;//p为新结点,指向最后一个元素
    
    for (int i=1 ; i<=n; ++i)
    {
        p = (LNode *)malloc(sizeof(LNode));
        p->data = i;
        p->next = L->next;//将p的next指向L的next
        L->next = p;//将L的next指向p
    }
    
    return L;
}

尾插法

/**
 
 1.2创建链表(尾插法) 时间复杂度O(n)
 
 */
LinkList * CreateListTail(int n)
{
    LNode *L = NULL;
    L = (LNode *)malloc(sizeof(LNode));
    L->next = NULL;
    
    LNode *r = L;
    
    LNode *p = NULL;
    
    for (int i=1 ; i<=n; ++i)
    {
        p = (LNode *)malloc(sizeof(LNode));
        p->data = i;
        p->next = NULL;
        
        r->next = p;//将r的next指向p
        r = p;//将r指向p的指向
    }
        
    return L;
}

2.单链表查找

/**
 
 2.查找元素(取第i个元素) 时间复杂度O(n)
 
 */

int GetElemFromLinkList(LinkList *L, int i, ElemType *e)
{
    LNode *node = L;//设node为第i-1个结点

    while (i!=0 && node!=NULL) {
        --i;
        node = node->next;
    }
    
    if (i==0 && node != NULL) {

        *e = node->data;
        return 0;
        
    } else {
        
        return -1;//第i个元素不存在
    }
}

3.单链表插入

/**
 
 3.插入元素 时间复杂度为O(n),但是频繁插入时,为O(1)
    在第i个元素位置,插入数据e
 
 */

int LinkListInsert(LinkList *L, int i, ElemType e)
{
    LNode *p = L;//设p为第i-1个结点

    while(i!=0 && p!=NULL) {
        --i;
        p = p->next;
    }
    
    if (i==0 && p!=NULL) {
        LNode *s = (LNode*)malloc(sizeof(LNode));
        s->data = e;
        
        s->next = p->next;//s的直接后继指向p原来的直接后继
        p->next = s;//p的直接后继指向s
        
        return 0;
    } else {
        return -1;
    }
}

4.单链表删除

/**
 
 4.插入元素 时间复杂度为O(n),但是频繁删除时,为O(1)
    删除第i个节点
 
 */
int LinkListDelete(LNode *L, int i, ElemType *e)
{
    LNode *p = L;//设p为第i-1个结点
    
    while(i!=0 && p!=NULL) {
        --i;
        p = p->next;
    }
    
    if (i==0 && p!=NULL) {
        LNode *q = p->next;
        p->next = q->next;
        *e = q->data;
        
        return 0;
    } else {
        return -1;
    }
}

5.清空单链表

/**
 
 5.清空单链表 时间复杂度为O(n)
 
 */
int ClearLinkList(LinkList *L)
{
    LNode *p, *q;
    p = L->next;
    
    while (p != NULL) {
        q = p->next;
        free(p);
        p = q;
    }
    
    L->next = NULL;
    
    return 0;
}

测试代码如下:

    // 创建链表:头插法
    LinkList *l1 = CreateListHead(10);
    
    //输出链表中的数据
    while (l1->next != NULL) {
        LNode *node = l1->next;
        printf("%d ", node->data);
        l1 = node;
    }
    printf("\n");
    
    // 创建链表:尾插法
    LinkList *l2 = CreateListTail(10);
    
    //输出链表中的数据
    while (l2->next != NULL) {
        LNode *node = l2->next;
        printf("%d ", node->data);
        l2 = node;
    }
    printf("\n");
    
    // 查找第7个节点
    LinkList *l3 = CreateListTail(10);
    int xdata = 0;
    int status = GetElemFromLinkList(l3, 7, &xdata);// 返回7
    
    // 查找第7个节点位置插入777
    status = LinkListInsert(l3, 7, 777);
    
    GetElemFromLinkList(l3, 8, &xdata);// 返回777

    // 删除第i个节点
    status = LinkListDelete(l3, 4, &xdata);
    
    // 清空单链表
    status = ClearLinkList(l3);
    //输出链表中的数据
    while (l3->next != NULL) {
        LNode *node = l3->next;
        printf("%d ", node->data);
        l2 = node;
    }
    printf("\n");

demo地址

相关文章

  • 数据结构梳理 — 线性表

    线性表:由 >=0 个数据元素组成的有限序列(线性表有两种存储结构:顺序存储结构和链式存储结构) 一. 顺序存储结...

  • 目录 - 数据结构

    总目录 数据结构 第01局:绪论 数据结构 第02局:线性表 上 数据结构 第03局:线性表 下 数据结构 第04...

  • iOS设计模式--迭代器

    学习迭代器之前,先看一种数据结构--线性表 线性表:线性表是最基本,最简单,也是最常用的一种数据结构。 线性表中数...

  • Java造轮子-数据结构-线性表

    数据结构-线性表 @(数据结构) 线性表是数据结构中的逻辑结构。可以存储在数组上,也可以存储在链表上。 顺序表(数...

  • 数据结构与算法02——线性表

    一、 线性表线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的一种,一...

  • 2020-07-02

    算法和数据结构梳理 线性表 顺序表数组(移动、原地操作、前缀和)多数组(合并 交集二维数组(旋转、数独、染色、置零...

  • 23-二叉树基础(上):什么样的二叉树适合用数组来存储?

    前面讲的都是线性表结构,栈、队列等等。今天讲一种非线性表结构,树。树这种数据结构比线性表的数据结构要复杂得多,内容...

  • 数据结构之线性表

    数据结构之线性表 1. 什么是线性表 线性表是一种最常用,最简单的一种数据结构。它是n个数据元素的有限序列。n 为...

  • 玩转数据结构之线性表

    0. 序言 学习数据结构的第一步,让我们来了解下线性表。 1. 概念 线性表是最基本的数据结构。一个线性表是由N个...

  • 栈和队列

    栈和队列是两种应用非常广泛的数据结构,它们都来自线性表数据结构,都是“操作受限”的线性表。 栈 栈(Stack):...

网友评论

      本文标题:数据结构梳理 — 线性表

      本文链接:https://www.haomeiwen.com/subject/fphrmxtx.html