数据结构与算法学习笔记之线性表三---单链表的表示和实现(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;
}
相关推荐
xiaoyalian1 小时前
R语言绘图过程中遇到图例的图块中出现字符“a“的解决方法
笔记·r语言·数据可视化
南东山人1 小时前
一文说清:C和C++混合编程
c语言·c++
Red Red2 小时前
网安基础知识|IDS入侵检测系统|IPS入侵防御系统|堡垒机|VPN|EDR|CC防御|云安全-VDC/VPC|安全服务
网络·笔记·学习·安全·web安全
贰十六3 小时前
笔记:Centos Nginx Jdk Mysql OpenOffce KkFile Minio安装部署
笔记·nginx·centos
知兀3 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
Ysjt | 深4 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
ephemerals__4 小时前
【c++丨STL】list模拟实现(附源码)
开发语言·c++·list
Microsoft Word4 小时前
c++基础语法
开发语言·c++·算法
Natural_yz4 小时前
大数据学习17之Spark-Core
大数据·学习·spark