数据结构之线性表-C语言描述

顺序存储结构和链式存储结构

线性表存储数据可细分为以下 2 种:
1.将数据依次存储在连续的整块物理空间中,这种存储结构称为顺序存储结构(简称顺序表);
2.数据分散的存储在物理空间中,通过一根线保存着它们之间的逻辑关系,这种存储结构称为链式存储结构(简称链表);

也就是说,线性表存储结构可细分为顺序存储结构和链式存储结构。

一:顺序表

顺序表的存储结构定义

#define Size 5
typedef struct Table{
    int *head;//声明了一个名为head的长度不确定的数组,也叫“动态数组”
    int length;//记录当前顺序表的长度
    int size;//记录顺序表分配的存储容量
}table;

顺序表中基本操作的实现

#include <stdio.h>
#include <stdlib.h>
#define Size 5

typedef struct Table
{
    int *head;      //存储空间的基地址
    int length;   //当前长度
    int size;     //顺序表的大小
}table;

//顺序表的初始化
table InitTable()
{
    table t;
    t.head=(int*)malloc(Size*sizeof(int));
    if(t.head == NULL)
    {
        printf("初始化失败\n");
        exit(0);
    }
    t.length=0;
    t.size=Size;
    return t;
}

//顺序表的插入
table addElem(table t,int elem,int index)
{
    if(index<1 || index>t.length+1)
    {
        printf("插入的位置有误\n");
        return t;
    }

    if (t.length>=t.size)
    {
        t.head=(int *)realloc(t.head, (t.size+1)*sizeof(int));
        if (t.head == NULL)
        {
            printf("存储分配失败\n");
        }
        t.size+=1;
    }

    for(int i=t.length-1;i>=index-1;i--)
    {
        t.head[i+1]=t.head[i];
    }
    t.head[index-1]=elem;
    t.length++;
    return t;
}

//顺序表的遍历
void displayTable(table t)
{
    for(int i=0;i<t.length;i++)
    {
        printf("%d ",t.head[i]);
    }
    printf("\n");
}

//顺序表的查找
int SelectElem(table t,int index)
{
    for(int i=0;i<t.length;i++)
    {
        if(index==i+1)
        {
            return t.head[i];
        }
    }
    return -1;
}

//顺序表的删除
table deleteElem(table t,int index)
{
     if (index>t.length || index<1) {
        printf("被删除元素的位置有误\n");
        return t;
    }
    for(int i=index;i<=t.length-1;i++)
    {
        t.head[i-1]=t.head[i];
    }
    t.length--;
    return t;
}

//顺序表的修改
table updateElem(table t,int elem,int index)
{
    for(int i=0;i<=t.length-1;i++)
    {
        if(index == i+1)
        {
            t.head[i]=elem;
        }
    }
    return t;
}

int main()
{
    table t;
    t=InitTable();
    for(int i=1;i<=Size;i++)
    {
        t.head[i-1]=i;
        t.length++;
    }
    displayTable(t);
    int a = SelectElem(t,2);
    printf("%d\n",a);
    t = addElem(t,100,2);
    displayTable(t);
    t = deleteElem(t,2);
    displayTable(t);
    t = updateElem(t,666,5);
    displayTable(t);
    return 0;
}

二:链表

1.单链表

头节点,头指针和首元节点
一个完整的链表需要由以下几部分构成:

头指针:一个普通的指针,它的特点是永远指向链表第一个节点的位置。很明显,头指针用于指明链表的位置,便于后期找到链表并使用表中的数据;

节点:链表中的节点又细分为头节点、首元节点和其他节点:
头节点:其实就是一个不存任何数据的空节点,通常作为链表的第一个节点。对于链表来说,头节点不是必须的,它的作用只是为了方便解决某些实际问题;

首元节点:由于头节点(也就是空节点)的缘故,链表中称第一个存有数据的节点为首元节点。首元节点只是对链表中第一个存有数据节点的一个称谓,没有实际意义;

其他节点:链表中其他的节点;

单链表的存储结构定义

typedef struct LNode
{
    int data;
    struct LNode *next;
} LNode,*LinkList;

单链表基本操作的实现

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

typedef struct LNode
{
    int data;
    struct LNode *next;
} LNode,*LinkList;

//采用头插法创建链表
LinkList createList1()
{
    LinkList head;
    int length,x;
    head=(LinkList)malloc(sizeof(LinkList));
    head->next=NULL;
    printf("请输入节点的个数\n");
    scanf("%d",&length);
    for(int i=0; i<length; i++)
    {
        LinkList p;
        p=(LinkList)malloc(sizeof(LinkList));
        p->next=NULL;
        printf("请输入要存储的数:\n");
        scanf("%d",&x);
        p->data=x;
        p->next=head->next;
        head->next=p;
    }
    return head;
}

//采用尾插法创建链表
LinkList createList2()
{
    LinkList head;
    int length,x;
    head=(LinkList)malloc(sizeof(LinkList));
    head->next=NULL;
    LinkList r=head;
    printf("请输入结点个数\n");
    scanf("%d",&length);
    for(int i=0; i<length; i++)
    {
        LinkList p;
        p=(LinkList)malloc(sizeof(sizeof(LinkList)));
        p->next=NULL;
        printf("请输入要存储的数:\n");
        scanf("%d",&x);
        p->data=x;
        r->next=p;
        r=p;
    }
    return head;
}

//单链表的遍历
void dispList(LinkList head)
{
    LinkList p=head;
    printf("链表中的数据如下:\n");
    while((p->next)!=NULL)
    {
        printf("%d\n",p->next->data);
        p=p->next;
    }
}

//单链表的插入
LinkList addElem(LinkList head,int elem,int add)
{
    LinkList p=head;
    for(int i=1; i<add; i++)
    {
        p=p->next;
        if (p == NULL)
        {
            printf("插入位置无效\n");
            return p;
        }
    }
    LinkList c;
    c=(LinkList)malloc(sizeof(LinkList));
    c->data=elem;
    c->next=p->next;
    p->next=c;
    return head;
}

//删除指定位置的结点
LinkList deleteElem(LinkList head,int del)
{
    LinkList p=head;
    for(int i=1; i<del; i++)
    {
        p=p->next;
        if(p->next==NULL)
        {
            printf("结点不存在!!\n");
            return p;
        }
    }
    LinkList d=p->next;
    p->next=p->next->next;
    free(d);
    return head;
}

//删除所有结点数据域值为x的结点,结点不唯一
LinkList delnode(LinkList head, int x)
{
    LinkList p=head;
    while(p->next!=NULL){
        LinkList a = p->next;
        if(a->data==x){
            p->next=a->next;
            free(a);
        }else{
            p=p->next;
        }
    }
    return head;
}

//采用头插法逆置单链表
LinkList Inverse(LinkList head)
{
    LinkList p,q;
    p = head->next;
    head->next=NULL;
    while(p!=NULL){
        q = p->next;
        p->next = head->next;
        head->next = p;
        p = q;
    }
    return head;
}

int main()
{
    LinkList head=createList2();
    dispList(head);

    head = Inverse(head);
    printf("逆置后元素排序:\n");
    dispList(head);

    printf("请输入要删除的节点数据\n");
    int data;
    scanf("%d",&data);
    head = delnode(head,data);
    dispList(head);

    printf("请输入要插入的位置\n");
    int elem,add;
    scanf("%d",&add);
    printf("请输入要插入的数值\n");
    scanf("%d",&elem);
    head=addElem(head,elem,add);
    dispList(head);

    printf("请输入要删除的位置\n");
    int del;
    scanf("%d",&del);
    head=deleteElem(head,del);
    dispList(head);
    return 0;
}

2.循环链表

在这里插入图片描述

若将两个线性表合并成一个表时,仅需要将第一个表的尾指针指向第二个表的第一个结点,第二个表的尾指针指向第一个表的头结点,然后释放第二个表的头结点。

p = B->next->next;
B->next = A->next;
A->next = p;

3.双向链表

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小小本科生debug

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

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

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

打赏作者

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

抵扣说明:

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

余额充值