简单数据结构之线性表之链表

—— 引子

今天给大家带来的是一个新的数据结构,链表!

上一次的顺序表,大家一定觉得非常的容易,没错,作为一个入门级别的数据结构,要是让大家感觉到吃力,那还了得!

一起来回顾一下我们上次的顺序表,作为一个比较简单的数据结构,顺序表利用自身的管理结构,完成了对于整个结构的控制,利用结构体将三个参数封装起来,size用来表示当前顺序表中一共有多少元素,而capacity表示最大可以储存多少元素,最后,还有这一个指针,用来指向一片堆区中的连续空间,用来真正的保存我们的数据。

相信现在大家听到我的介绍,恐怕陌生感要减少很多了吧,所以,不要放弃,要相信,熟能生巧,总有一天,这区区数据结构,你一定是能将他拿下的!


什么是链表?

对于链表这个数据结构,相信很多小伙伴还是比较头疼的,放心,等会,就让你完全弄懂它!

首先,链表的关键,在窝瓜看来,就是这个“链”字!

我想佛珠大家一定都见过,窝瓜觉得,佛珠的整体形态就和我们的链表有着异曲同工之妙!

在这里插入图片描述
首先,我们可以将每一颗珠子看成是我们的一个节点,而这珠子与珠子之间的线,我们就将其想象为一个看的见、摸得到的指针,这样,每一颗佛珠,就可以通过这条线,找到下一个佛珠,这不正是我们的链表吗!

现在我们来模拟一下链表的实现!

首先,桌面上什么都没有,当我们插入第一个元素的时候,桌面上出现了一个佛珠(也就是一个节点),这时,我们又需要第二颗佛珠,首先,将线从第一颗佛珠上穿过,然后拿出第二颗佛珠,用线将其串在第一颗佛珠的后面,以此类推,这种用线将佛珠一颗颗串在一起的过程,在链表中,就是我们的插入操作!

此时我们发现其中一颗佛珠的品相不好,不想要它了,我们要怎么将它去掉呢?

很多小伙伴一定会说,这也太简单了,直接把线间断,然后把珠子取出来,然后将断了的线连接上,不就好了!

没错,就是这么简单!其实在我们链表的世界中,也是这样的,上面的情况,就完美的模拟了我们删除节点的情况,在删除节点的时候,我们只需要将要删除节点的前一个节点找到,然后切断这个节点与要删除节点之间的线(指针),然后将这个节点直接指向要删除节点的后一个节点,这不就完成了所谓的删除操作。

所以说,链表其实也不难!

接下来,就让我们看看怎样用代码模拟上面的过程,从而实现我们的链表!


链表的实现

上次介绍了顺序表的特点,那么,链表有着什么特点呢?让我们一起来看看!

链表的特点:
  1. 空间不固定,随用随建,避免浪费
  2. 逻辑上每个节点相邻,物理上不一定
  3. 插入和删除比较简单,不用遍历整个结构
  4. 查询因为没有索引的缘故,性能不如顺序表,时间复杂度为O(n)
定义头节点和节点
typedef struct N{
    int data;
    struct N * next;
}Node;
//节点

typedef struct{
    Node * head;
    Node * tail;
    int size;
}List;
//头节点
初始化链表
List * init_list(List * p){
    p->head = (void *)0;
    p->tail = (void *)0;
    p->size = 0;
    return p;
}//初始化链表
清空链表
List * clear_list(List * p){
    while(p->head){
        Node * del = p->head;
        p->head = del->next;
        free(del);
    }
    p->tail = (void *)0;
    p->size = 0;
    return p;
}//清空链表
销毁链表
void * destroy_list(List * p){
    clear_list(p);
}//销毁链表
尾插法
List * push_back_list(List * p, int data){
    Node * new_node = make_node(data);
    if(!new_node){
        return (void *)0;
    }
    p->tail->next = new_node;
    p->tail = new_node;
    p->size++;
    return p;
}//尾部插入元素
头插法
List * push_front_list(List * p, int data){
    Node * new_node = make_node(data);
    if(!new_node){
        return (void *)0;
    }
    new_node->next = p->head;
    p->head = new_node;
    p->size++;
    if(p->size == 1){
        p->tail = new_node;
    }
    return p;
}//头部插入元素
头删法
List * pop_front_list(List * p){
    if(p->size == 0){
        return (void *)0;
    }
    Node * del = p->head;
    p->head = p->head->next;
    free(del);
    p->size--;
    if(p->size == 0){
        p->tail = (void *)0;
    }
    return p;
}//头部删除元素
尾删法
List * pop_back_list(List * p){
    if(p->size == 0){
        return (void *)0;
    }
    Node * del = p->tail;
    Node * tem = p->head;
    if(p->size == 1){
        p->head = p->tail = (void *)0;
    }else{
        while(tem->next != p->tail){
            tem = tem->next;
        }
        tem->next = (void *)0;
        p->tail = tem;
    }
    free(del);
    p->size--;
    return p;
}//尾部删除元素
打印链表
void print(List * p){
    Node * tem = p->head;
    if(tem){
        printf("现在有%d个元素,分别是:%d",p->size, tem->data);
        tem = tem->next;
        while(tem){
            printf("、%d",tem->data);
            tem = tem->next;
        }
        printf("\n");
    }else{
        printf("链表为空!\n");
    }
}//打印链表
查找指定元素位置
Node * find_list(List * p, int data){
    if(p->size == 0){
        return (void *)0;
    }
    Node * tem = p->head;
    while(tem && tem->data == data){
        tem = tem->next;
    }
    return tem;
}//查找指定元素
删除指定位置元素
List * erase_list(List * p, Node * pos){
    if(p->size == 0 || pos == p->tail){
        return (void *)0;
    }
    if(pos == (void *)0){
        return pop_back_list(p);
    }
    Node * del = pos->next;
    pos->next = del->next;
    p->size--;
    if(del == p->tail){
        p->tail = pos;
    }
    free(del);
    return p;
}//删除指定
在指定位置插入元素
List * insert_list(List * p, Node * pos, int data){
    if(p->size == 0 || pos == (void *)0){
        return push_front_list(p , data);
    }
    if(pos == p->tail){
        return push_back_list(p , data);
    }
    Node * new_node = make_node(data);
    if(!new_node){
        return (void *)0;
    }
    new_node->next = pos->next;
    pos->next = new_node;
    p->size++;
    return p;
}//在指定位置插入元素
测试代码
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int main()
{
    int i;
    List list;
    init_list(&list);
    push_front_list(&list, 1);
    push_front_list(&list, 2);
    print(&list);
    push_back_list(&list, 3);
    push_back_list(&list, 4);
    print(&list);
    pop_front_list(&list);
    pop_back_list(&list);
    print(&list);
    insert_list(&list,find_list(&list, 3) , 5);
    print(&list);
    erase_list(&list, find_list(&list, 5));
    print(&list);
    clear_list(&list);
    print(&list);
    destroy_list(&list);
    return 0;
}
结果展示

在这里插入图片描述

这就是这次给大家带来的关于链表的实现,下次,将会给大家带来顺序栈和链式栈的实现!谢谢大家~~~~~~~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章