数据结构C语言之线性表

发现更多计算机知识,欢迎访问Cr不是铬的个人网站

1.1线性表的定义

线性表是具有相同特性的数据元素的一个有限序列
对应的逻辑结构图形:

file

从线性表的定义中可以看出它的特性:

(1)有穷性:一个线性表中的元素个数是有限的

(2)一致性:一个线性表中所有元素的性质相同,即数据类型相同

(3)序列性:各个元素的相对位置是线性的

1.2线性表的抽象数据类型描述

(如下图所示)

file

那为什么要引进这个数据结构呢?那就不得不谈谈它的作用了。

线性表的作用体现在两个方面:

a. 当一个线性表实现后,程序员加油直接使用它来存放数据,即作为存放数据的容器

b.使用线性表的基本运算来完成更复杂的运算

2.1线性表的顺序存储结构——顺序表

线性表的顺序存储结构简称为顺序表

file

(如图为线性表到顺序表的映射)

需要注意的是顺序表采用数组进行实现,但是不是任意数组可以作为一个顺序表,二者运算是不同的

下图为顺序表的存储示意图
file

2.2顺序表的基本运算实现

(1)结构体SqList定义

//数据元素
typedef int ElemType;
//结构体
typedef struct
{
    ElemType data[MaxSize];
    //数据长度
    int length;
}SqList;

(2)建立顺序表

//建立顺序表
void CreateList(SqList*& L, ElemType a[], int n)
{
    int i = 0, k = 0;
    //记得一定要分配内存空间 
    L = (SqList*)malloc(sizeof(SqList));
    while (i < n)
    {
        //将a[i]存储到L中
        L->data[k] = a[i];
        k++; i++;
    }
    L->length = k;
}

(3)初始化线性表

void InitList(SqList*& L)
{
    L = (SqList*)malloc(sizeof(SqList));
    L->length = 0; //置空线性表的长度为0
}

(4)销毁线性表

void DestroyList(SqList*& L)
{
    free(L);//释放L所指的顺序表空间
}

(5)判断是否为空

bool ListEmpty(SqList* L)
{
    return(L->length == 0);
}

(6)求线性表长度

int ListLength(SqList* L)
{
    return (L->length);
}

(7)求表中某个值

bool GetElem(SqList* L, int i, ElemType& e)
{
    if (i<1 || i > L->length)
        return false;
    e = L->data[i - 1];
    return true;    //成功找到元素返回true
}

(8)按照元素值查找

int LocateElem(SqList* L,ElemType e)
{
    int i = 0;
    while (i < L->length && L->data[i] != e)
        i++;
    if (i >= L->length)
        return 0;
    else
        return i + 1;       //返回逻辑序号
}

(9)输出线性表

void DisplayList(SqList* L)
{
    for (int i = 0; i < L->length; i++)
        printf("%d", L->data[i]);
    printf("\n");
}

(10)完整代码

#include<iostream>
using namespace std;
const int MaxSize = 1005;
typedef int ElemType;
typedef struct
{
    ElemType data[MaxSize];
    int length;
}SqList;

//建立顺序表
void CreateList(SqList*& L, ElemType a[], int n)
{
    int i = 0, k = 0;
    //记得一定要分配内存空间 
    L = (SqList*)malloc(sizeof(SqList));
    while (i < n)
    {
        L->data[k] = a[i];
        k++; i++;
    }
    L->length = k;
}
//初始化线性表
void InitList(SqList*& L)
{
    L = (SqList*)malloc(sizeof(SqList));
    L->length = 0; //置空线性表的长度为0
}
void DestroyList(SqList*& L)
{
    free(L);//释放L所指的顺序表空间
}
bool ListEmpty(SqList* L)
{
    return(L->length == 0);
}

int ListLength(SqList* L)
{
    return (L->length);
}
void DisplayList(SqList* L)
{
    for (int i = 0; i < L->length; i++)
        printf("%d", L->data[i]);
    printf("\n");
}
bool GetElem(SqList* L, int i, ElemType& e)
{
    if (i<1 || i > L->length)
        return false;
    e = L->data[i - 1];
    return true;    //成功找到元素返回true
}
int LocateElem(SqList* L,ElemType e)
{
    int i = 0;
    while (i < L->length && L->data[i] != e)
        i++;
    if (i >= L->length)
        return 0;
    else
        return i + 1;       //返回逻辑序号
}
bool ListInsert(SqList*& L, int i, ElemType e)
{
    int j;
    if (i < 1 || i >L->length + 1 || L->length == MaxSize)
        return false;
    i--;
    for (j = L->length; j > i; j--)
        L->data[j] = L->data[j - 1];
    L->data[i] = e;
    L->length++;
    return true;
}
bool ListDelete(SqList*& L, int i, ElemType& e)
{
    int j;
    //特判是否符合 
    if (i < 1 || i>L->length)
        return false;
    i--;
    for (int j = i; j < L->length - 1; j++)
        L->data[j] = L->data[j + 1];
    L->length--;
    return true;
}
void delnodel(SqList*& L, ElemType x)
{
    int k = 0;
    for (int i = 0; i < L->length; i++)
        if (L->data[i] != x)
        {
            L->data[k] = L->data[i];
            k++;
        }
    L->length = k;
}

}
int main() {
    SqList* L;
    int a[10] = { 7,5,7,7,9,1,6,2,4,8 };
    CreateList(L, a, 10);

    DisplayList(L);
}

2.3线性表的链式存储结构——链表

线性表的链式存储就是链表,每个链表存储点不仅包括数据域,还有指针域。

链表示意图如下:

file

2.4 单链表算法实现

(1)数据结构声明

typedef int ElemType;
typedef struct LinkNode
{
    ElemType data;      //存放元素值
    struct LinkNode* next;  //指向后继结点

}LinkNode;

建立单链表有两种方法:头插法和尾插法

(2)头插法

//建立单链表
void CreatListF(LinkNode*& L, ElemType a[], int n)
{
    LinkNode* s;
    //创建头结点 
    L = (LinkNode*)malloc(sizeof(LinkNode));
    L->next = NULL; //头结点指针域置NULL
    for (int i = 0; i < n; i++)
    {
        s = (LinkNode*)malloc(sizeof(LinkNode));//重新分配空间
        s->data = a[i];
        s->next = L->next;
        L->next = s;
    }
}

(3)尾插法

void CreatListR(LinkNode*& L, ElemType a[], int n)
{
    LinkNode* s, * r;
    //创建头结点
    L = (LinkNode*)malloc(sizeof(LinkNode));
    r = L;                      //r始终指向尾结点,初始时指向头结点
    for (int i = 0; i < n; i++)
    {
        s = (LinkNode*)malloc(sizeof(LinkNode));//重新分配空间
        s->data = a[i];
        r->next = s;
        r = s;
    }
    //尾结点的nextt域置为NULL
    r->next = NULL;         
}

(4)初始化

void InitList(LinkNode*& L)
{
    L = (LinkNode*)malloc(sizeof(LinkNode));
    L->next = NULL;
}

(5)销毁表

void DestroyList(LinkNode*& L)
{
    LinkNode* pre = L, * p = L->next;   //pre指向p的前驱结点
    while (p != NULL)
    {
        free(pre);
        pre = p;
        p = pre->next;
    }
    free(pre);      //循环结束时p为NULL,pre指向尾结点
}

(6)输出表

void DispList(LinkNode* L)
{
    LinkNode* p = L->next;//指向头结点
    while (p!=NULL)
    {
        printf("%d", p->data);
        p = p->next;
    }
    printf("\n");
}

重点!!!

(7)链表的插入

bool ListInsert(LinkNode*& L, int i, ElemType e)
{
    int j = 0;
    LinkNode* p = L, * s;
    if (i <= 0)return false;//首结点的次序是一
    while (j < i - 1 && p != NULL)//找到第i-1个结点
    {
        j++;
        p = p->next;
    }
    if (p == NULL)
        return false;
    else
    {
        s = (LinkNode*)malloc(sizeof(LinkNode));
        //典中典
        s->data = e;
        s->next = p->next;
        p->next = s;
        return true;
    }
}

(8)删除某个元素

bool ListDelete(LinkNode*& L, int i, ElemType& e)
{
    int j = 0;
    LinkNode* p = L, * q;
    if (i <= 0)return false;//头结点是不计入其中的
    while (j < i - 1 && p != NULL)
    {
        j++;
        p = p->next;
    }       
    if (p == NULL)
        return false;
    else {
        q = p->next;
        if (q == NULL)
            return false;
        e = q->data;
        p->next = q->next;
        free(q);
        return true;
    }
}

最后介绍一下双链表

2.5双链表

(1)建立双链表

typedef int ElemType;
// 定义DlinkNode结构体
struct DlinkNode {
    int data;           // 数据域
    DlinkNode* prior;   // 前驱指针
    DlinkNode* next;    // 后继指针
};

同样的,双链表的建立也有头插法和尾插法

(2)头插法

// 定义CreateListF函数
void CreateListF(DlinkNode*& L, ElemType a[], int n)
{
    DlinkNode* s;
    L = (DlinkNode*)malloc(sizeof(DlinkNode)); // 创建头结点
    L->prior = L->next = NULL; // 先后指针域置NULL
    for (int i = 0; i < n; i++) // 循环创建数据结点
    {
        s = (DlinkNode*)malloc(sizeof(DlinkNode)); // 创建数据结点s
        s->data = a[i];
        s->next = L->next; // 将S插到头结点之后
        if (L->next != NULL)
            L->next->prior = s;
        L->next = s;
        s->prior = L;
    }
}

(3)尾插法

void CreateListR(DlinkNode*& L, ElemType a[], int n)
{
    DlinkNode* s,*r;
    L = (DlinkNode*)malloc(sizeof(DlinkNode)); // 创建头结点
    r = L;          //r始终指向尾结点,开始时指向头结点
    for (int i = 0; i < n; i++) // 循环创建数据结点
    {
        s = (DlinkNode*)malloc(sizeof(DlinkNode)); // 创建数据结点s
        s->data = a[i];
        r->next = s; s->prior = r;      //将s结点插入到r结点之后
        r = s;                          //r指向尾结点
    }
    r->next = NULL;
}

2.6总结

线性表是一种基础且重要的数据结构,常见的线性表有三种实现方式:顺序表、单链表和双链表。

本文对这三种线性表的实现方式及特点做一个简要总结:

一、顺序表顺序表是将逻辑顺序上相邻的数据元素存储在物理位置上也相邻的存储单元中,通常使用数组来实现。- 特点:定位直接,通过下标操作即可快速访问任一位置的节点;实现简单。

缺点:插入删除需要移动大量元素,效率低;存储空间固定,扩容不灵活。

二、单链表单链表通过链式存储结构实现,每个节点除存储数据外,还储存下一个节点的地址信息。

-特点:存储灵活,可动态扩展,插入删除简单,效率高。-

缺点:访问任一节点需要从头结点遍历,无法直接定位

三、双链表双链表相比单链表,每个节点增加一个指向前驱节点的指针,实现双向链表。-

特点:可双向遍历链表,操作更灵活。-

缺点:每个节点存储空间略大于单链表。

**综上,三种线性表各有特点,使用需根据具体场景需求选择合适的数据结构。顺序表操作简单,链表存储灵活,双链表可以双向访问。开发时需要权衡效率与实现难度,选择最优实现。**

本文由博客一文多发平台 OpenWrite 发布!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,841评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,415评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,904评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,051评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,055评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,255评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,729评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,377评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,517评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,420评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,467评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,144评论 3 317
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,735评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,812评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,029评论 1 256
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,528评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,126评论 2 341

推荐阅读更多精彩内容