数据结构与算法学习笔记之线性表三---单链表的表示和实现(C++)

目录

前言

一、顺序表的优缺点

二、单链表的表示和实现

1.初始化

2.清空表

3.销毁

4.表长

5.表空

6.获取表中的元素

7.下标

8.直接前驱

9.直接后继

10.插入

11.删除

12.遍历链表

13.测试代码


前言

这篇博客主要介绍单链表的表示和实现。

一、顺序表的优缺点

线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理位置上也相邻,因此可以随机存取表中任一元素,它的存储位置可用一个简单直观的公式来表示。当然这种存储结构也存在弱点:在作插入或删除操作时,需移动大量元素。

二、单链表的表示和实现

单链表的两个要素:数据域,指针域。其中数据域表示的是当前结点的数据,指针域指向的下一个结点的地址。

单链表的定义如下:

cpp 复制代码
// - - - - - 线性表的单链表存储结构 - - - - -
typedef int ElemType;
typedef int Staus;
typedef struct LNode {
    ElemType data;          // 数据域
    struct LNode *next;     // 指针域
} LNode, *LinkList;

1.初始化

cpp 复制代码
// 链表初始化
Staus initLinkList(LinkList &linkList) {
    linkList = new LNode;   // 创建头结点
    if (!linkList) {        // 内存分配失败
        return false;
    }
    linkList->next = nullptr; // 头结点的指针域置空
    return true;
}

2.清空表

遍历单链表,置空指针

cpp 复制代码
// 清空链表
void clearLinkList(LinkList &linkList) {
    LinkList p, q;
    p = linkList->next;
    while (p) {
        q = p;
        p = p->next;
        delete q;
    }
    linkList->next = nullptr;
}

3.销毁

cpp 复制代码
// 销毁链表
void destroyLinkList(LinkList &linkList) {
    clearLinkList(linkList);
    delete linkList;
    linkList = nullptr;
}

4.表长

cpp 复制代码
// 表长
int linkListLength(LinkList &link){
    LNode * p =  link->next;
    int len = 0;
    while (p) {
        p = p->next;
        len++;
    }
    return len;
}

5.表空

cpp 复制代码
// 表空
Status linkListEmpty(LinkList &link){
    return linkListLength(link) == 0;
}

6.获取表中的元素

cpp 复制代码
// 获取表中的元素
Status getElemLinkList(LinkList &link,int pos,ElemType * element){
    if (pos < 1|| pos > linkListLength(link)) {
        return 0;
    }
    LinkList p = link->next;
    int j = 1;
    while (p && j < pos) {
        p = p ->next;
        ++j;
    }
    if (!p ||j > pos) {
        return 0;
    }
    *element = p->data;
    return 1;
}

7.下标

cpp 复制代码
// 获取数据元素element下标
Status getLocateinkList(LinkList &link,ElemType element,int * location){
    LinkList p = link->next;
    int j = 1;
    while (p) {
        if (p->data == element) {
            * location = j;
            return 1;
        }
        p = p ->next;
        ++j;
    }
    return 0;
}

8.直接前驱

cpp 复制代码
// 直接前驱
Status priorElemLinkList(LinkList &link,ElemType current,ElemType * priorElement){
    LinkList p = link->next;
    LinkList head = link;
    int j = 1;
    while (p) {
        if (p->data == current) {//找到数据元素
            if (j > 1) {
                * priorElement = head->data;
                return 1;
            }
        }
        p = p ->next;
        head = head->next;
        ++j;
    }
    return 0;
}

9.直接后继

cpp 复制代码
// 直接后继
Status nextElemLinkList(LinkList &link,ElemType current,ElemType * nextElement){
    LinkList p = link->next;
    while (p) {
        if (p->data == current) {//找到数据元素
            if (p -> next != nullptr) {
                * nextElement = p->next->data;
                return 1;
            }
        }
    }
    return 0;
}

10.插入

cpp 复制代码
// 单链表插入
Status insertLinkList(LinkList &head, int pos, int element) {
    if (pos < 1) {      // 位置非法
        return 0;
    }
    LinkList p = head;
    int j = 0;
    while (p && j < pos - 1) {
        p = p->next;
        ++j;
    }
    if (!p || j > pos - 1) {
        return 0;
    }

    LinkList q = new LNode; // 生成新节点
    if (!q) {               // 内存分配失败
        return 0;
    }
    q->data = element;
    q->next = p->next;
    p->next = q;
    return 1;
}

11.删除

cpp 复制代码
// 单链表删除
Status deleteLinkList(LinkList &head, int pos) {
    if (pos < 1 || !head->next) {  // 位置非法或空链表
        return false;
    }
    LinkList p = head;
    int j = 0;
    while (p->next && j < pos - 1) { // 找到要删除结点的前一个结点
        p = p->next;
        ++j;
    }
    if (!p->next || j > pos - 1) {   // 删除位置超出范围
        return false;
    }
    LinkList q = p->next;   // 要删除的结点
    p->next = q->next;      // 前一个结点指向后一个结点
    delete q;               // 释放删除结点的内存
    return true;
}

12.遍历链表

cpp 复制代码
// 遍历链表
void traverseList(LinkList linkList) {
    LinkList p = linkList->next;
    while (p) {
        cout << p->data << " ";
        p = p->next;
    }
    cout << endl;
}

13.测试代码

cpp 复制代码
void testLinkList(void){
    LinkList myList;
    if (!initLinkList(myList)) {
        cout << "链表初始化失败!" << endl;
    }
    cout<<"表长:"<<linkListLength(myList)<<endl;
    int values[] = {1, 2, 3, 4, 5};
    int size = sizeof(values) / sizeof(values[0]);
    if (!createLinkList(myList, values, size)) {
        cout << "创建链表失败!" << endl;
        destroyLinkList(myList); // 避免内存泄漏
    }

    cout << "链表元素:";
    traverseList(myList);
    cout<<"表长:"<<linkListLength(myList)<<endl;
    
    cout << "获取某个位置的数据元素"<<endl;
    for (int i = -1; i <= 6; i++) {
        int element;
        if (getElemLinkList(myList, i, &element)) {
            cout<<"第"<<i<<"个数据元素获取成功,数据元素为:"<<element<<"\t"<<endl;
        }else{
            cout<<"第"<<i<<"个数据元素获取失败!"<<endl;
        }
    }
    cout<<endl;
    cout << "获取单链表数据元素下标"<<endl;
    for (int i = -1; i <= 6; i++) {
        int locate;
        if (getLocateinkList(myList, i, &locate)) {
            cout<<"数据元素"<<i<<"下标获取成功,下标为:"<<locate<<"\t"<<endl;
        }else{
            cout<<"数据元素"<<i<<"下标获取失败!"<<endl;
        }
    }
    cout<<endl;
    cout << "获取单链表数据元素直接前驱"<<endl;
    for (int i = -1; i <= 6; i++) {
        int element;
        if (priorElemLinkList(myList, i, &element)) {
            cout<<"数据元素"<<i<<"直接前驱为:"<<element<<"\t"<<endl;
        }else{
            cout<<"数据元素"<<i<<"没有直接前驱!"<<endl;
        }
    }

    // 插入元素
    int insertPos = 3;
    int insertElement = 10;
    if (!insertLinkList(myList, insertPos, insertElement)) {
        cout << "插入元素失败!" << endl;
        destroyLinkList(myList); // 避免内存泄漏
    }

    cout << "插入后的链表元素:";
    traverseList(myList);

    // 删除元素
    int deletePos = 2;
    if (!deleteLinkList(myList, deletePos)) {
        cout << "删除元素失败!" << endl;
        destroyLinkList(myList); // 避免内存泄漏
    }

    cout << "删除后的链表元素:";
    traverseList(myList);

    // 清空链表
    clearLinkList(myList);
    cout << "链表已清空!" << endl;

    // 销毁链表
    destroyLinkList(myList);
    cout << "链表已销毁!" << endl;
}
相关推荐
m0_74823388几秒前
黑马程序员JavaWeb开发教程(前端部分) ---笔记分享
前端·笔记
m0_6938093811 分钟前
Python——day09
python·学习
1101 110120 分钟前
STM32-笔记10-手写延时函数(SysTick)
笔记·stm32·单片机
LeonNo1125 分钟前
golangb并发,Sync包中Mutes,WaitGroup, NewCond的适应
学习
2401_8582861129 分钟前
117.【C语言】数据结构之排序(选择排序)
c语言·开发语言·数据结构·笔记·算法·排序算法
捕鲸叉31 分钟前
C++软件设计模式之类型模式和对象型模式
开发语言·c++·设计模式
thesky1234561 小时前
活着就好20241226
学习·算法
td爆米花1 小时前
C#冒泡排序
数据结构·算法·排序算法
1101 11011 小时前
STM32-笔记8-433M点灯
笔记
1101 11011 小时前
STM32-笔记14-排队控制系统
笔记·stm32·嵌入式硬件