单链表---c 语言B版

单链表的介绍

1.什么是单链表

线性表的链式存储又称为单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表节点,除存放自身的信息外,还需要存放一个指向其后继的指针

2.单链表和顺序表的对比

顺序表可以随机访问表中的任意元素,但插入和删除需要移动大量的元素。链式存储线性表时,不需要使用地址连续的存储单元,它通过链建立起元素之间的关系,所以插入和删除不需要移动元素,只需要修改指针,但也会失去顺序表可随机存储的优点利用单链表可以解决顺序表大量连续储存单元的缺点,单链表存在指针域,有浪费空间的缺点。在查找某个特定的结点时,需要从表头遍历,依次查找。

单链表的实现

1.单链表的定义

typedef int SLTDateType;
typedef struct SListNode
{
    SLTDateType data;
    struct SListNode* next;
}SLTNode;

单链表的data是用来保存数据的,我们对data重命名这样当我们需要保存不同类型的数据时候便于修改,同时单链表也需要定义一个指针去存储下一个结点的地址。

2.单链表的尾插

void SLTpushBack(SLTNode** phead, SLTDateType x)
{
    SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//结辟节点
    if (newnode == NULL)
    {
        perror("malloc fail");
        return;
    }
    newnode->data = x;
    newnode->next = NULL;//结点赋值
    if (*phead == NULL)
    {
        *phead = newnode;
    }
    else
    {
        SLTNode* tail = *phead;
        while (tail->next != NULL)
        {                          //结点插入
            tail = tail->next;
        }
        tail->next = newnode;
    }
}

时间复杂度O(N)。

单链表的尾插首先开辟一个新的节点,然后让链表最后一个元素的next指向新的结点,新结点的next指向下一个节点也就是NULL,这样让链表进行链接起来。单链表只能找到下一个节点的位置,想要找到前一个节点的位置必须从头开始遍历,因此这样效率很低。

3.单链表的头插

void SLTpushFront(SLTNode* *head, SLTDateType x)
{
    assert(*head);
    SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
    if (newnode == NULL)
    {
        perror("malloc fail");
        return;
    }
    newnode->data = x;
    newnode->next = NULL;
    newnode->next = *head;
    *head = newnode;
}

这里的传入的是指针的地址,要想修改它必须要用二级指针。想改变int需要用int*,要想改变int*需要int**,也就是二级指针。我们定义的是一个结构体指针变量,传入的是结构体指针变量的地址,要想改变指针变量必须用二级指针结构体指针的变量的地址一定要非空,而链表可能非空所以我们必须对代码进行断言操作。

单链表每个结点的插入时间复杂度为O(1),设单链表的长度为n,总时间复杂度为O(N)。

4.单链表的头删

void SLTpopFront(SLTNode** head)
{
    assert(*head);
    SLTNode* first = *head;
    *head = first->next;
    free(first);
    first = NULL;
}

首先定义一个first指针,然后找到phead->next的地址,释放掉phead 的空间,让phead重新 指向phead->next。该算法的时间复杂度为O(1)。

5.单链表尾删

void SLTpopBack(SLTNode** head)
{
    assert(*head);
    if ((*head)->next == NULL)
    {
        free(*head);
        *head = NULL;
    }
    else
    {
        SLTNode* prev = NULL;
        SLTNode* tail = *head;
        while (tail->next != NULL)
        {
            prev = tail;
            tail = tail->next;
        }
        free(tail);
        prev->next = NULL;
    }
}

尾部删除要改变前一个节点的next指针,需要遍历节点,时间复杂度为O(N)。

6.删除pos后的数据

void SLTease(SLTNode** head, SLTNode* pos)
{
    assert(head);
    assert(pos);
    SLTNode* prev = *head;
    while (prev->next != pos)
    {
        prev = prev->next;
    }
    prev->next = pos->next;
    free(pos);
    pos = NULL;

}

要删除某个结点通常做法是先从链表的头结点找到前驱节点,然后执行删除操作,实际就是将其后继节点的值给本身,然后删除后继点。

7.在pos位置后插入数据

void SLTinsert(SLTNode** head,  SLTNode* pos, SLTDateType x)
{
    assert(pos);
    assert(head);
    SLTNode* prev = *head;
    while (prev->next != pos)
    {
        prev = prev->next;
    }

    SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
    if (newnode == NULL)
    {
        perror("malloc fail");
        return;
    }
    newnode->data = x;
    newnode->next = NULL;
    prev->next = newnode;
    newnode->next = pos;
}
  1. 单链表的打印

void SLTprint(SLTNode* head)
{
    SLTNode* tail = head;
    while (tail)
    {
        printf("%d->", tail->data);
        tail = tail->next;
    }
    printf("NULL\n");
}

  1. 单链表的数据查找

void SLTFind(SLTNode* head, SLTDateType x)
{
    SLTNode* cur = head;
    while (cur)
    {
        if (cur->data == x)
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}

总代码

#include"slist.h"
void Test()
{
    SLTNode* plist=NULL;
    SLTpushBack(&plist, 1);
    SLTpushBack(&plist, 2);
    SLTpushBack(&plist, 3);
    SLTpushBack(&plist, 4);
    SLTprint(plist);
    SLTpushFront(&plist, 9);
    SLTprint(plist);
    SLTpopFront(&plist);
    SLTprint(plist);
    SLTpopBack(&plist);
    SLTprint(plist);
    SLTinsert(&plist, 2, 3);
    SLTprint(plist);
    SLTease(&plist, 2);
    SLTprint(plist);
    SLTFind(plist, 3);

}
int main()
{
    Test();
    return 0;
}

#include"slist.h"

void SLTpushBack(SLTNode** phead, SLTDateType x)
{
    SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
    if (newnode == NULL)
    {
        perror("malloc fail");
        return;
    }
    newnode->data = x;
    newnode->next = NULL;
    if (*phead == NULL)
    {
        *phead = newnode;
    }
    else
    {
        SLTNode* tail = *phead;
        while (tail->next != NULL)
        {
            tail = tail->next;
        }
        tail->next = newnode;
    }
}
void SLTprint(SLTNode* head)
{
    SLTNode* tail = head;
    while (tail)
    {
        printf("%d->", tail->data);
        tail = tail->next;
    }
    printf("NULL\n");
}
void SLTpushFront(SLTNode* *head, SLTDateType x)
{
    SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
    if (newnode == NULL)
    {
        perror("malloc fail");
        return;
    }
    newnode->data = x;
    newnode->next = NULL;
    newnode->next = *head;
    *head = newnode;
}
void SLTpopFront(SLTNode** head)
{
    assert(*head);
    SLTNode* first = *head;
    *head = first->next;
    free(first);
    first = NULL;
}
void SLTpopBack(SLTNode** head)
{
    assert(*head);
    if ((*head)->next == NULL)
    {
        free(*head);
        *head = NULL;
    }
    else
    {
        SLTNode* prev = NULL;
        SLTNode* tail = *head;
        while (tail->next != NULL)
        {
            prev = tail;
            tail = tail->next;
        }
        free(tail);
        prev->next = NULL;
    }
}
void SLTinsert(SLTNode** head,  SLTNode* pos, SLTDateType x)
{
    assert(pos);
    assert(head);
    SLTNode* prev = *head;
    while (prev->next != pos)
    {
        prev = prev->next;
    }

    SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
    if (newnode == NULL)
    {
        perror("malloc fail");
        return;
    }
    newnode->data = x;
    newnode->next = NULL;
    prev->next = newnode;
    newnode->next = pos;
}
void SLTease(SLTNode** head, SLTNode* pos)
{
    assert(head);
    assert(pos);
    SLTNode* prev = *head;
    while (prev->next != pos)
    {
        prev = prev->next;
    }
    prev->next = pos->next;
    free(pos);
    pos = NULL;

}
void SLTFind(SLTNode* head, SLTDateType x)
{
    SLTNode* cur = head;
    while (cur)
    {
        if (cur->data == x)
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}
#include<stdlib.h>
typedef int SLTDateType;
typedef struct SListNode
{
    SLTDateType data;
    struct SListNode* next;
}SLTNode;
void SLTpushBack(SLTNode** phead, SLTDateType x);
void SLTprint(SLTNode* head);
void SLTpushFront(SLTNode** head, SLTDateType x);
void SLTpopFront(SLTNode** head);
void SLTpopBack(SLTNode** head);
void SLTinsert(SLTNode** head, SLTNode* pos, SLTDateType);
void SLTease(SLTNode** head, SLTNode* pos);
void SLTFind(SLTNode* head, SLTDateType x);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值