【数据结构】【C语言】单链表

名词解释

线性存储结构

  • 顺序表,链表

链表(Linked List)

  • 别名链式存储结构,单链表
  • 用于存储逻辑关系为“一对一”的数据
  • 与顺序表不同,不限制数据的物理存储状态
  • 由一系列的节点(Node)组成
  • 每个节点保存了数据元素和指向下一个节点的指针
  • 链表中的节点可以动态的添加和移除
  • 相较于静态数组,在插入和删除操作时具有更好的小v
  • 有单链表,双向链表,循环链表三种
  • 单链表,节点只有一个指针指向下一个节点
  • 双向链表,在单链表的基础上增加了前向指针
  • 循环链表,在单链表的基础上增加了尾节点指向头节点的指针
  • 链表内存不是一段连续的存储空间,通过指针进行连接
  • 链表需要通过遍历整个链表才能找到指定节点,因此对于频繁访问特定位置的数据,使用链表不是最优选择

节点

  • 由数据域和指针域组成
  • 数据元素本身,所在的区域被称为【数据域】
  • 指向直接后继元素的指针,所在的区域被称为【指针域】
  • 分为【头节点】【首元节点】【其他节点】

头节点

  • 不存任何数据的空姐点,通常作为链表的第一个节点。
  • 对于链表来说,头节点不是必需的
  • 方便解决部分问题

首元节点

  • 由于头节点的缘故,链表中第一个存有数据的节点被称为首元节点

头指针

  • 一个普通的指针
  • 永远指向链表第一个节点的位置
  • 头指针用于指明链表的位置,便于后期查找链表并使用链表中的数据
  • 链表有头节点时,头指针指向头节点;反之,若链表中没有头节点,则头指针指向首元节点

单链表

单链表常用于实现栈、队列和哈希表等数据结构,也常用于算法问题的解决。

优点

  1. 内存动态分配:单链表采用动态内存分配,可以根据需求动态地分配节点,不会浪费内存空间。

  2. 插入、删除快:单链表的插入和删除操作只需要改变指针域,不需要移动数据,因此效率较高。

  3. 灵活性强:单链表支持在链表中任意位置插入、删除结点,可以灵活地适应数据变化。

  4. 空间利用率高:单链表的每个结点只需要存储一个指针域和一个数据域,相比数组,空间利用率更高。

  5. 可以有效防止内存泄露:因为单链表的每个节点都是通过动态分配内存来创建的,所以可以避免不必要的内存泄露问题。

缺点

  1. 随机访问困难:单链表只能顺序访问,要访问其中某个元素,需要从头开始依次访问,直到找到所需元素,因此随机访问效率低下。

  2. 空间浪费:由于每个节点需要额外的指针来指向下一个节点,因此单链表的存储空间比同样数量的元素的数组要多。

  3. 删除节点需要额外操作:要删除某个节点,必须先找到其前驱节点,然后将其指向后继节点,这个过程需要额外的操作。

  4. 不能逆向访问:由于单链表的节点只有一个指向后继节点的指针,没有指向前驱节点的指针,因此不能逆向访问。

  5. 对于一些应用场景,单链表不能满足需求。例如要求访问某个节点前面的节点,就需要从头开始遍历,效率较低。

初始化

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

typedef struct Link
{
    char elem; //数据域
    struct Link * next; //指针域,指向后继元素
}link; //link为节点名,每个节点都是一个link结构体

link * initLink();
link * initLink_2();
void display(link *p);
void display_2(link *p);

//无头结点链表
link * initLink()
{
    link * p = NULL; //创建头指针
    link * temp = (link *)malloc(sizeof(link));//创建首元节点

    //首元节点初始化
    temp->elem = 1;
    temp->next = NULL;

    // 头指针指向首元节点
    p = temp;

    //从第二个节点开始创建
    for(int i = 2; i < 5; i++)
    {
        link *a = (link *)malloc(sizeof(link));
        a->elem = i;
        a->next = NULL;

        temp->next = a;
        temp = temp->next
    }


    return p;
}

//存储{1,2,3,4},有头节点链表
link * initLink_2()
{
    link * p = (link *)malloc(sizeof(link)); //创建头节点
    link * temp = p; //声明一个指针指向头节点

    //生成链表
    for(int i = 1; i < 5; i++)
    {
        link *a = (link *)malloc(sizeof(link));
        a->elem = i;
        a->next = NULL;
        temp->next = a;
        temp = temp->next;
    }

    return p;
}

//不带头节点
void display(link *p)
{
    link *temp = p; //将temp指针重新指向头结点

    //只要temp指针指向的结点的next不是NULL,就执行输出语句
    while(temp)
    {
        printf("%d", temp->elem);
        temp = temp->next;
    }

    printf("\n");
}

//带有头节点
void display(link *p)
{
    link *temp = p;

    while(temp->next)
    {
        temp = temp->next;
        printf("%d", temp->elem);
    }

    printf("\n");
}

增删改查

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

typedef struct Link
{
    int elem;
    struct  Link * next;
}link;


link *initLink();
void displayLink(link *l);
link *addLink(link *l, int elem, int add);
link *deletLink(link *l, int add);
link *amendLink(link *l, int add, int newElem);
int selectLink(link *l, int elem);


//有头节点
link *initLink()
{
    link *p = (link *)malloc(sizeof(link));//
    link * temp = p;//声明一个指针指向头节点

    for(int i = 1; i < 9; i++)
    {
        link *a = (link *)malloc(sizeof(link));
        a->elem = i;
        a->next = NULL;

        temp->next = a;
        temp = temp->next;
    }

    return p;
}


//有头节点
void displayLink(link *l)
{
    link *temp = l;
    //temp = temp->next;

    while(temp->next)
    {
        temp = temp->next;
        printf("%d", temp->elem);
    }

    printf("\n");
}


link *addLink(link *l, int elem, int add)
{
    link * temp = l;
    //temp = temp->next;

    for(int i = 1; i < add; i++)
    {
        temp = temp->next;
        if(NULL == temp)
        {
            printf("插入位置无效\n");
            return l;
        }
    }

    //创建插入节点
    link *c = (link *)malloc(sizeof(link));
    c->elem = elem;

    //向链表插入元素
    c->next = temp->next;
    temp->next = c;

    return l;
}

link *deletLink(link *l, int add)
{
    link *temp = l;

    for(int i = 1; i < add; i++)
    {
        temp = temp->next;
        if(temp->next == NULL)
        {
            printf("没有该节点\n");
            return l;
        }
    }

    link *del = temp->next;
    temp->next = temp->next->next;

    free(del);
    
    return l;
}

link *amendLink(link *l, int add, int newElem)
{
    link *temp = l;
    temp = temp->next;

    for(int i = 1; i < add; i++)
    {
        temp = temp->next;
    }
    
    temp->elem = newElem;

    return l;
}

int selectLink(link *l, int elem)
{
    link *temp = l;
    int i = 1;

    while(temp->next)
    {
        temp = temp->next;
        if(temp->elem == elem)
        {
            return i;
        }
        i++;
    }

    return -1;
}

int main()
{
    //初始化
    link *p = initLink();
    displayLink(p);

    //第4位插入数据5
    p = addLink(p, 5, 4);
    displayLink(p);

    //删除元素3
    p = deletLink(p, 3);
    displayLink(p);

    //查找元素2的位置
    int address = selectLink(p, 2);
    printf("%d\n", address);

    //更改第3位置的数据为7
    amendLink(p, 3, 7);
    displayLink(p);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45117176/article/details/132008136
今日推荐