单链表

单链表的定义

定义一个单链表

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)。

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

上一篇:线性表-三种链表


下一篇:单链表