单链表及其用法

一、链表的定义

链表是一种物理存储单元上非连续、非顺序的存储结,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表是由一系列结点组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域。

二、链表的存储结构

链表的存储结构是链式存储,链式存储的特点是用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素与其直接后继数据元素之间的逻辑关系,对数据元素来说,出来存储其本身的数据元素的信息之外,还需存储一个直接后继的的信息,也就是直接后继的存储位置。

它的结构图就像下面一样


三、单链表的操作

单链表的操作同样有构造空表,销毁链表,增加元素,删除元素,逆置,排序……我们也通过一个例子来说明它所有的操作:

#include<stdio.h>
#include<malloc.h>
typedef struct NODELIST
{
    int data;
    struct NODELIST *next;
}nodelist;
nodelist *createList(int a) //创建一个有a个元素的链表,输入其值
{
    nodelist *head, *p, *q;
    head = (nodelist *)malloc(sizeof(nodelist));
    p = head;
    for(int i=1;i<=a;i++)
    {
        q = (nodelist *)malloc(sizeof(nodelist));
        p->next = q;
        q->data = i;
        p = q;
    }
    p->next = NULL;
    return head;
}
void destroyNodeList(nodelist *head) //销毁此链表
{
    if(head == NULL)
        return;
    if(head->next == NULL)
    {
        free(head);
        head = NULL;
        return;
    }
    nodelist *p = head->next;
    while(p!=NULL)
    {
        nodelist *q = p;
        p = p->next;
        free(q);
    }
    free(head);
    head = NULL;
}
void Print(nodelist *head)  //遍历整个链表,并且打印其数据域的元素
{
    nodelist *p;
    p = head->next;
    while(p)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}
void InsertList(nodelist *head, int i, int data)//在第i个位置之前插入元素data
{
    int j = i-1;
    nodelist *p, *q;
    p = head;
    while(j--)
        p = p->next;
    q = (nodelist *)malloc(sizeof(nodelist));
    q->next = p->next;
    q->data = data;
    p->next = q;
}
void InsertLast(nodelist *head, int data)//在链表尾部插入一个元素data
{
    nodelist *p, *q;
    p = head;
    while(p->next)
        p = p->next;
    q = (nodelist *)malloc(sizeof(nodelist));
    q->data = data;
    p->next = q;
    q->next = NULL;
}
void deleteList(nodelist *head, int data) //删除元素 data
{
    nodelist *p, *q = head;
    p = head->next;
    while(p)
    {
        if(p->data == data)
            break;
        p = p->next;
        q = q->next;
    }
    q->next = p->next;
    free(p);
}
void reverseList(nodelist *head) //链表逆序
{
    if(head == NULL || head->next == NULL)
        return;
    nodelist *p = head->next;
    nodelist *q = p->next;
    nodelist *t = NULL;
    while(q!=NULL)
    {
        t = q->next;
        q->next = p;
        p = q;
        q = t;
    }
    (head->next)->next = NULL;
    head->next = p;
}
void sortlist(nodelist *head) //排序(降序)
{
    nodelist *p, *q, *t;
    if(head->next == NULL || head == NULL)
        return;
    p = head;
    q = p->next;
    t = p->next;
    for(;q!=NULL;q = q->next)
        for(t=q->next;t!=NULL;t=t->next)
        {
            if(q->data > t->data)
            {
                int a = q->data;
                q->data = t->data;
                t->data = a;
            }
        }
}
int main()
{
    int a;
    NODELIST *head;
    scanf("%d", &a);
    head = createList(a);
    InsertList(head, 3, 0);
    Print(head);
    InsertLast(head, 5);
    Print(head);
    deleteList(head, 3);
    Print(head);
    reverseList(head);
    Print(head);
    sortlist(head);
    Print(head);
    destroyNodeList(head);

    return 0;
}

链表的操作就是我上面写的程序。那么我们在什么时候选择使用链表呢,链表给我们带来了什么好处》

链表的优点如下:

我们再插入删除元素的时候,不需要移动大量的元素,效率很高;链表的存储密度低,对内存的利用率很高;使用链表可以很方便的扩展所占空间的大小。

链表的缺点如下:

我们只能通过指针去顺序访问元素,如果要进行读取元素,它的复杂度是O(n),效率很低。

所以我们如果要进行大量的删除和插入元素的操作,而读取元素的操作不多的情况下,我们使用链表是一个很好的选择!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值