线性表-单链表学习笔记(基础)

one-to-one

单链表具体实现方案:给每一个元素配置一个指针,每个指针都指向相邻的下一个元素。(“链”字的由来)

单链表可以由什么组成?
一个结点(节点)的构成: 数据域 指针域(Next 域)
头指针: 类型跟指针一样,但是它的特点是永远指向链表中的第一个结点
结点们 头结点: 有时为了方便操作,特意在链表开头留一个空结点(代表它数据域不正常利用)
首元结点: 特指链表开头第一个存有了数据的结点
其它结点: 链表中其它的结点
#include 
#include 

#define ElemType char
//typedef char ElemType

/*结点结构体*/
typedef struct Node{
    ElemType data; //数据域
    struct Node* next; //指针域
}Node, *PNode; 
/*单链表结构体*/
typedef struct LinkList {
    PNode first; //指向头结点
    PNode last; //指向尾结点
    size_t size; //记录有效结点数
}LinkList;
/*初始化*/
void init(LinkList* ll) 
{
    ll->first = ll->last = (Node*)malloc(sizeof(Node)); //为ll的头、尾结点申请内存空间
    //assert(ll->first != NULL); //断言语句assert()确保ll->first!=NULL
    if (ll->first == NULL)
        return;
    ll->first->next = NULL; //初始化头结点的指针域
    ll->size = 0; //初始化ll的结点数
}
/*判空*/
int empty(LinkList* ll)
{
    if (ll->size == 0)
        return 1;
    else
        return 0;
}
/*长度*/
size_t size(LinkList* ll)
{
    return ll->size;
}
/*尾插*/
void push_back(LinkList* ll, ElemType value)
{
    PNode p = (Node*)malloc(sizeof(Node)); //申请内存空间
    //assert(p != NULL); //断言语句判断
    if (p == NULL)
        return;
    p->data = value; //设置值
    p->next = NULL; //初始化next域

    ll->last->next = p; //将结点放到链表尾部
    ll->last = p; //包裹指针下移
    ll->size++; //增加结点数
}
/*头插*/
void push_front(LinkList* ll, ElemType value)
{
    PNode p = (Node*)malloc(sizeof(Node)); //申请内存空间
    //assert(p != NULL); //断言语句判断
    if (p == NULL)
        return;
    p->data = value; //设置值

    p->next = ll->first->next;
    ll->first->next = p;
    if (ll->size == 0)
    {
        ll->last = p;
    }
    ll->size++; //增加结点数
}
/*尾删*/
void pop_back(LinkList* ll)
{
    if (ll->size == 0) //判断链表是否还有结点?
        return; //直接退出
    PNode p = ll->first; //缓冲变量p
    while (p->next != ll->last) //先找到倒数第二个结点,再代替
        p = p->next; //下移指针
    free(ll->last); //释放内存
    ll->last = p; //取代
    ll->last->next = NULL; //初始化尾结点的指针域
    ll->size--; //减少结点数
}
/*头删*/
void pop_front(LinkList* ll)
{
    if (ll->size == 0)
        return;
    PNode p = ll->first->next; //临时保存首元结点的地址
    ll->first->next = p->next; //解除连接
    free(p); //释放内存
    if (ll->size == 1)
        ll->last = ll->first;
    ll->size--;
}
/*值查找*/
Node* find(LinkList* ll, ElemType key)
{
    PNode p = ll->first->next;
    while (p!=NULL && p->data!=key)
        p = p->next;
    return p;
}
/*输出*/
void display(LinkList* ll)
{
    PNode p = ll->first->next;
    while (p != NULL)
    {
        printf("%c -> ", p->data);
        p = p->next;
    }
    printf("Nul.\n");
}
int main() {
    LinkList ll = { NULL, NULL, 0 };
    init(&ll);
    printf("此单链表是否为空?(1代表true,0代表false)\n%d\n", empty(&ll));
    push_back(&ll, 'h');
    push_back(&ll, 'e');
    push_back(&ll, 'l');
    push_back(&ll, 'l');
    push_back(&ll, 'o');
    printf("插入hello的单链表的长度:%d\n", size(&ll));
    display(&ll);
    free(ll.first); //释放
    free(ll.last); //释放
}

链表和顺序表的区分

链表 顺序表
内存申请时机 需要提前申请 什么时候存储,什么时候申请
复用性 一次开辟,永久使用(除了动态数组) 随用随开
空间利用率 链表 < 顺序表(链表明显容易产生空间碎片)
时间复杂度 链表适合操作元素,顺序表适合访问查找元素

你可能感兴趣的:(学习,笔记,数据结构)