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

775 阅读4分钟

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

下面是几个有关线性链表常用的算法:

1. 建立一个线性链表

设线性表为A=(a1, a2, a3, ..., an),建立与A对应的线性链表。

  • 设线性链表的第1个链结点的指针为list

建立一个线性链表的过程是一个动态生成链结点并依次将他们链接到链表中的过程。 算法思想: image.png 算法:

LinkList CREAT(int n) 
{
    LinkList p, r, list = NULL;
    ElemType a;
    int i;
    for (i = 1; i <= n; i++)
    {
        READ(a); // 获取一个数据元素
        p = (LinkList)malloc(sizaof(LNode)); // 申请一个新的链结点
        p->data = a;
        p->link = NULL; // 链表末尾结点指针域置空
        if (list == NULL)
            list = p;
        else 
            r->link = p; // 将新结点链接在链表尾部
        r = p; // 指针变量r总是指向链表末尾
    }
    return(list)
}

算法的时间复杂度: O(n)

2. 求线性链表的长度

线性链表的长度:链表中包含的结点的个数

算法思想:

image.png 具体算法:

int LENGTH(LinkList list)
{
    LinkList p = list;
    int n = 0;
    while(p != NULL) {
        n++;
        p = p->link; // 指针p指向下一个链结点
    }
    return n; // 返回链表长度
}
// -----------------------------------
// 递归算法:线性链表是一种递归结构,每个链结点的指针域都指向一个线性链表(该结点的后继线性链表),它所指向的链结点为该单链表的第1个链结点
int LENGTH(LinkList list)
{
    if (list != NULL)
        return 1 + LENGTH(list->link);
    else
        return 0;
}

**时间复杂度:**O(n)

3. 测试线性链表是否为空表

int ISEMPTY(LinkList list)
{
    return list == NULL;
    // 如果是带有头结点的链表,空表只有一个头结点,此时list指向头结点,头结点的指针域为NULL,判断语句修改为:
    return list->link == NULL;
}

时间复杂度: O(1)

4. 确定元素item在线性链表中的位置

算法思想:

image.png 算法:

LinkList FIND(LinkList list, ElemType item)
{
    LinkList p = list;
    while(p != NULL && p->data != item)
    {
        p = p->link;
    }
    return p;
}

时间复杂度: O(n)

5. 在非空线性表的第1个链结点前插入一个数据信息为item的链结点 ※

算法思想:

算法:

void INSERTLINK1(LinkList &list, ElemType item)
{
    // list 中存放链表的首地址
    LinkList p;
    p = (LinkList)malloc(sizeof(LNode)); // 申请一个新的链结点
    p->data = item; // 将item设置为新结点的数据域
    p->link = list; // 将list设置为新结点的指针域
    list = p; // list指向新结点
}

时间复杂度: O(1)

6. 在非空线性链表的末尾插入一个数据信息为item的链结点 ※

算法思想:

image.png 算法:

void INSERTLINK2(LinkList list, ElemType item)
{
    // list中存放链表的首地址
    LinkList p, r;
    r = list;
    while(r->link != NULL)
    {
        r = r->link; // 找到链表末尾结点的地址
    }
    p = (LinkList)malloc(sizeof(LNode)); // 申请一个新的链结点
    p->data = item; // 新结点的数据域设置为item
    p->link = NULL; // 新结点的指针域设置为NULL
    r->link = p; // 插入链表的末尾
}

时间复杂度:

7. 在线性链表中由指针q指出的链结点后面插入一个数据信息为item的链结点

算法思想:

image.png 算法:

void INSERTLINK3(LinkList &list, LinkList q, ElemType item)
{
    // list中存放链表的首地址,item为被插入元素
    LinkList p;
    p = (LinkList)malloc(sizeof(LNode)); // 生成一个新的链结点
    p->data = item; // 新结点的数据域设置为item
    if (list == NULL) { // 当链表为空时
        list = p;
        p->link = NULL;
    } else { // 当链表非空时
        p->link = q->link;
        q->link = p;
    }
}

时间复杂度: O(1)

8. 在线性链表中第i个链结点后面插入一个数据信息为item的链结点

算法思想:

image.png 算法:

int INSERTLINK4(LinkList list, int i, ElemType item)
{
    LinkList p, q = list;
    int j;
    j = 1;
    while(j < i && q != NULL) {
        q = q->link;
        j++;
    } // 寻找第i个链结点
}
if (j != i || q == NULL) {
    ERRORMESSAGE("链表中不存在第i个链结点!");
    return -1; // 插入失败,返回-1
}
p = (LinkList)malloc(sizeof(LNode)); // 申请一个新的链结点
p->data = item;
p->link = q->link;
q->link = p; // 将新链结点插在第i个链结点之后
return 1; // 插入成功,返回1

9. 在按值有序链接的线性链表中插入一个数据信息为item的链结点

算法思想:

image.png 算法:

void INSERTLINK5(LinkList &list, ElemType item)
{
    LinkList p, q, r;
    p = (LinkList)malloc(sizeof(LNode)); // 生成一个新的链结点
    p->data = item;
    if (list == NULL || item < list->data) { // 若链表为空或者item小于第1个链结点
        p->link = list; // 将新的链结点插在链表最前面
        list = p;
    } else {
        q = list;
        while (q != NULL && item >= q->data) { // 寻址插入位置
            r = q;
            q = q->link;
        }
        p->link = q;
        r->link = p; // 将新的链结点插在q指示的链结点后面
    }
}

时间复杂度: O(n)