从0开始学习数据结构-线性链表的基本算法②

180 阅读3分钟

这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战

10. 从非空线性链表中删除q所指的链结点

算法思想:

image.png 算法:

void DELETELINK1(LinkList &list, LinkList r, LinkList q)
{
    // list中存放链表的首地址
    if (q == list)
        list = q->link; // 删除链表的第1个链结点
    else 
        r->link = q->link; // 删除q指示的那个链结点
    free(q); // 释放被删除链结点的空间
}

void DELETELINK2(LinkList &list, LinkList q) 
{
    // list中存放链表的首地址
    LinkList r;
    if (q == list) {
        list = q->link; // 删除链表的第1个链结点
        free(q); // 释放被删除链结点的空间
    } else {
        r = list;
        while((r->link != q) && (r->link != NULL)) { // 寻址q指示结点的直接前驱节点
            r = r->link;
            if (r->link != NULL) {
                r->link = q->link; // 删除q指示的链结点
                free(q); // 释放被删除链结点的空间
            }
        }
    }
}

11. 销毁一个线性链表

算法思想:

image.png 算法:

void DELETELIST(LinkList &list) 
{
    // list 中存放链表的首地址
    LinkList p = list;
    while (p != NULL) {
        list = p->link; // 保存下一个链结点的位置
        free(p); // 删除并释放当前链结点
        p = list; // 下一个链结点成为当前链结点
    }
}

时间复杂度: O(n)

12. 删除线性链表中数据域值为item的所有链结点

算法思想:

image.png 算法:

void DELETELIST(LinkList &list, ElemType item)
{
    // list 中存放链表的首地址
    LinkList p, q = list;
    p = list->link; // p指向第2个链结点
    while (p != NULL) {
        if (p->data == item) { p指向的链结点满足条件
            q->link = p->link; // 删除p指向的链结点
            free(p); // 释放被删除链结点的存储空间
            p = q->link; // p指向被删除链结点的下一个链结点
        } else {
            q = p;
            p = p->link; // p指到下一个链结点
        }
    }
    if (list->data == item) { // 第1个链结点满足条件
        q = list;
        list = list->link; // 删除第1个链结点
        free(p);
    }
}

时间复杂度: O(n)

13. 逆转一个线性链表

算法思想:

image.png 算法:

void INVERT(LinkList &list) 
{
    // list中存放链表的首地址
    LinkList p, q, r; // p q r都为活动指针
    p = list;
    q = NULL;
    while(p != NULL) {
        r = q;
        q = p;
        p = p->link;
        q->link = r;
    }
    list = q; // 链表逆转结束
}

时间复杂度:

14. 将两个非空线性链表连接成一个线性链表

算法思想:

image.png 算法:

void CONNECT(LinkList lista, LinkList listb) 
{
    LinkList p;
    for(p = lista; p->link; p = p->link); // 寻址第1个链表末尾结点的位置
    p->link = listb; // 将第2个链表链接到第1个链表末尾
}

时间复杂度: O(n)

15. 将两个按值有序链接的非空线性链表合并成为一个按值有序链接的线性链表

算法思想: image.png 算法:

LinkList MERGELIST(LinkList lista, LinkList listb)
{
    LinkList listc, p = lista, q = listb, r;
    if (lista->data <= listb->data) {
        listc = lista;
        r = lista;
        p = lista->link;
    } else {
        listc = listb;
        r = listb;
        q = listb->link;
    } // listc指向lista和listb所指结点中最小者
    while(p != NULL && q !== NULL) {
        if (p->data <= q->data) { // 若当前p所指结点的值不大于q所指结点的值
            r->link = p; // 将p所指结点连接到r所指结点之后
            r = p;
            p = p->link;
        } else {
            r->link = q; // 将q所指结点链接到r所指结点之后
            r = q;
            q = q->link;
        }
    }
    r->link = p ? p : q; // 插入剩余链结点
    return listc; // 返回合并后的链表的第1个链结点的值
}

时间复杂度: 若两个链表的长度为n与m,则上述算法的时间复杂度为O(n+m)

16. 复制一个线性链表

算法思想:

image.png 算法:

LinkList COPY(LinkList lista)
{
    LinkList listb;
    if (lista == NULL)
        return NULL;
    else {
        listb = (LinkList)malloc(sizeof(LNode));
        listb->data = lista->data;
        listb->link = COPY(lista->link);
    }
    return listb;
}

时间复杂度: O(n)

17. 利用线性链表进行数据排序

算法思想: 已知一个按值任意排列的数据元素序列,可以利用建立一个按值有序排列的线性链表的方法对其进行数据排序。 算法:

void LINKSORT(ElemType A[], int n)
{
    LinkList p, list = NULL;
    int i;
    for (i = 0; i < n; i++)
        INSERTLINK5(list, A[i]); // 建立一个有序线性链表
    p = list;
    i = 0;
    while (p != NULL) {
        A[i++] = p->data;
        p = p->link;
    }
}