单链表

单链表的定义#

定义一个单链表#

typedef struct LNode
{
    int data;
    struct LNode *next;
} LNode, *LinkList;

初始化不带头结点的单链表#

bool InitList(LinkList &L)
{
    L = NULL;
    return true;
}

初始化带头结点的单链表#

bool InitList(LinkList &L)
{
    L = (LNode *)malloc(sizeof(LNode)); //分配一个头结点
    if (L = NULL)
    { //内存不足,分配失败
        return false;
    }
    L->next = NULL; //头结点之后暂时还没有结点,所以指空
    return true;
}

单链表的插入#

按位序插入带头结点的单链表#

bool ListInsert(LinkList &L, int i, int e)
{
    if (i < 1)
    {
        return false;
    }
    LNode *p;  //用于指向当前扫描到的结点
    int j = 0; //p指向第几个结点
    p = L;    //p指向为头结点(第0个,不存数据)
    while (p != NULL && j < i - 1)
    {
        p = p->next;
        j++;
    }
    if (p == NULL)
    { //当i大于最后一个结点时,p最后指向空
        return false;
    }
    LNode *s = (LNode *)malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;
    p->next = s; //这两个指向不能变,要是p的next结点先指向s,s的后继结点会指向s本身
    return true;
}

最好情况时间复杂度:O(1);

最坏情况时间复杂度:O(n);

平均情况时间复杂度:O(n)。

按位序插入不带头结点的单链表#

bool ListInsert(LinkList &L, int i, int e)
{
    if (i < 1)
    {
        return false;
    }
    if (i == 1) //头结点插入
    {
        LNode *s = (LNode *)malloc(sizeof(LNode));
        s->data = e;
        s->next = L;
        L = s;
        return true;
    }
    LNode *p;
    int j = 1; //不带头结点,不是在第一个结点插入,所以p指针一开始是指向第一个结点
    p = L;
    while (p != NULL && j < i - 1)
    {
        p = p->next;
        j++;
    }
    if (p == NULL)
    {
        return false;
    }
    LNode *s = (LNode *)malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;
}

最好情况时间复杂度:O(1);

最坏情况时间复杂度:O(n);

平均情况时间复杂度:O(n)。

通过对比可知,带头结点的操作比不带头结点的操作相对简单。

指定结点的后插操作#

bool InsertNextNode(LNode *p, int e)
{
    if (p == NULL)
    {
        return false;
    }
    LNode *s = (LNode *)malloc(sizeof(LNode));
    if (s == NULL) //空间不足分配失败
    {
        return false;
    }
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;
}

时间复杂度:O(1)。

指定结点的前插操作#

bool InsertPriorNode(LNode *p, int e)
{
    if (p == NULL)
    {
        return false;
    }
    LNode *s = (LNode *)malloc(sizeof(LNode));
    if (s == NULL)
    {
        return false;
    }
    s->next = p->next;
    p->next = s;
    s->data = p->data;
    p->data = e;
    return true;
}

时间复杂度:O(1)。

单链表的删除#

按位序删除带头结点的单链表#

bool ListDelete(LinkList &L, int i, int &e)
{
    if (i < 1)
    {
        return false;
    }
    LNode *p;
    int j = 0;
    p = L;
    while (p != NULL && j < i - 1)
    {
        p = p->next;
        j++;
    }
    if (p == NULL || p->next == NULL) //i值不合法或者p结点已经是最后一个结点
    {
        return false;
    }
    LNode *q = p->next; //q指向被删除结点
    e = q->data;
    p->next = q->next;
    free(q);
    return true;
}

最好情况时间复杂度:O(1);

最坏情况时间复杂度:O(n);

平均情况时间复杂度:O(n)。

删除指定结点#

bool DeleteNode(LNode *p) //p是最后一个结点这段代码不行
{
    if (p == NULL)
    {
        return false;
    }
    LNode *q = p->next;
    p->data = q->data;
    p->next = q->next;
    free(q);
    return true;
}

时间复杂度:O(1)。

单链表的查找#

查找操作默认是带头结点的单链表

单链表的位序查找#

LNode *GetElem(LinkList L, int i)
{
    if (i < 0)
    {
        return NULL;
    }
    LNode *p;
    int j = 0;
    p = L;
    while (p != NULL && j < i)
    {
        p = p->next;
        j++;
    }
    return p;
}

平均情况时间复杂度:O(n)。

单链表的按值查找#

LNode *LocateElem(LinkList L, int e)
{
    LNode *p = L->next;
    while (p != NULL && p->data != e)
    {
        p = p->next;
    }
    return p;
}

平均情况时间复杂度:O(n)。

求单链表的长度(不带头结点)#

int Length(LinkList L)
{
    int len = 0;
    LNode *p = L;
    while (p->next != NULL)
    {
        p = p->next;
        len++;
    }
    return len;
}

平均情况时间复杂度:O(n)。

单链表的建立#

尾插法建立单链表#

LinkList List_TailInsert(LinkList &L)
{
    int x; //要插入的元素数值
    L = (LinkList)malloc(sizeof(LNode));
    L->next = NULL;
    LNode *s, *r = L;
    scanf("%d", &x);
    while (x != 9999)
    {
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;
        r = s;
        scanf("%d", &x);
    }
    r->next = NULL;
    return L;
}

平均情况时间复杂度:O(n)。

头插法建立单链表#

LinkList List_HeadInsert(LinkList &L)
{
    int x = 0;
    L = (LinkList)malloc(sizeof(LNode));
    L->next = NULL;
    LNode *s;
    scanf("%d", &x);
    while (x != 9999)
    {
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        s->next = L->next;
        L->next = s;
        scanf("%d", &x);
    }
    return L;
}

平均情况时间复杂度:O(n)。

头插法可以用于链表的逆置。

posted @   isxh  阅读(50)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示
主题色彩