07 一个完整的链表 代码

描述:

一个完整的链表,用C语言写成(使用了C++中的引用&知识)。

可实现链表的增删改查、清空、求长度等功能。

链表中节点的数据域类型为char型。

参考:

青岛大学-王卓 数据结构课:https://www.bilibili.com/read/cv3285768

代码地址:Github: https://github.com/VicentWYS/Datadtructure--LinkList

项目结构:

main.cpp:

#include <iostream>
#include<stdio.h>
#include<stdlib.h>
#include "function_for_LinkList.h"
using namespace std;

int main()
{
    printf("测试单链表:
");
    testLinkList();

    return 0;
}

function_for_LinkList.h:

#ifndef FUNCTION_FOR_LINKLIST_H_INCLUDED
#define FUNCTION_FOR_LINKLIST_H_INCLUDED

//函数结果状态代码
#define OK      '1'
#define ERROR   '0'

typedef char ElemType;

//节点
typedef struct Lnode{
    ElemType data;      //数据域
    struct Lnode *next;     //指针域
}Lnode, *LinkList;


//单链表初始化
void InitList_L(LinkList &L);

//判断链表是否为空(空表)
int ListEmpty(LinkList L);

//销毁单链表
void DestroyList_L(LinkList &L);

//清空链表,但保留头节点和头指针
void ClearList(LinkList &L);

//求表长
int ListLength_L(LinkList L);

//取值:取单链表中第i个元素的内容
ElemType GetElem_L(LinkList L, int i);

//按值查找
//根据指定数据获取改数据(第一次出现)所在位置(地址)
Lnode *LocateElem_L(LinkList L, ElemType e);

//按值查找2
//在链表L中查找值为e的数据元素的位置序号
//若查找失败,返回 0
int LocateElem_index_L(LinkList L, ElemType e);

//插入元素
int ListInsert_L(LinkList &L, int i, ElemType e);

//删除第i个节点
//首先定位到第i-1个节点
int ListDelete_L(LinkList &L, int i);

//建立单链表:头插法
void CreateList_H(LinkList &L, ElemType e);

//尾插法
//一次插入一个节点
void CreateList_R(LinkList &L, ElemType e);

//展示单链表
void DisList(LinkList L);

//测试
void   testLinkList();

#endif // FUNCTION_FOR_LINKLIST_H_INCLUDED

function_for_LinkList.cpp:

#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include "function_for_LinkList.h"

//单链表初始化
void InitList_L(LinkList &L){     //&指引用型变量
    L=(LinkList) malloc (sizeof(Lnode));
    L->next = NULL;
}

//判断链表是否为空(空表)
int ListEmpty(LinkList L){      //0:非空, 1:空
    if(L->next != NULL){        //非空
        return 0;
    }else{
        return 1;       //链表为空
    }
}

//销毁单链表
void DestroyList_L(LinkList &L){       //从头到尾逐个删除,彻底消灭所有节点
    Lnode *p;
    while(L){       //L非空
        p = L;      //p指向当前节点
        L = L->next;        //L指向下一节点
        free(p);       //销毁当前节点
    }
}

//清空链表,但保留头节点和头指针
void ClearList(LinkList &L){
    Lnode *p, *q;
    p = L->next;        //p指向首元节点
    while(p != NULL){
        q = p->next;        //q指向第二节点
        free(p);
        p = q;
    }//节点清空完毕
    L->next = NULL;        //将头节点next指为空
}

//求表长
int ListLength_L(LinkList L){       //从首元结点开始,依次计数所有节点
    LinkList p;
    p= L->next;     //p指向首元结点
    int length=0;
    while(p != NULL){       //p非空
        length++;        //遍历单链表,统计节点数
        p = p->next;        //指向下一节点
    }
    return length;
}

//取值:取单链表中第i个元素的内容
/*
从第一个节点顺链扫描,用指针p指向当前扫描到的节点, p初值:p=L->next;
变量 j 作为计数器,累计当前扫描过的节点数,j 初值为 1;
当 p 指向下一个节点时,j 加1;
j == i 时,p 所指的节点就是要找的第 i 个节点;
*/
ElemType GetElem_L(LinkList L, int i){       //获取线性表L中某个元素的内容,通过变量e返回
    Lnode *p;       //游标p,指向当前节点
    int j=1;     //计数器

    p = L->next;        //初始化
    while(p && j<i){       //向后扫描,直到p指向第i个元素或p为空
        p=p->next;      //理想情况,在j = i-1时,符合while条件,p指向第i个节点,j++变为i,此时再判断发现 j<i 不成立,所以跳出while循环,
        //跳出后,此时j = i,p指向的正好是第 i 个节点
        j++;
    }
    if(!p || j>i){
        return ERROR;       //找不到元素,返回'0',退出
    }
    return p->data;     //找到元素,返回其数据域
}

//按值查找
//根据指定数据获取改数据(第一次出现)所在位置(地址)
Lnode *LocateElem_L(LinkList L, ElemType e){
    //在链表L中查找值为e的数据元素
    //若找到,则返回L中值为e的数据元素的地址,
    //若找不到,则返回NULL
    LinkList p;
    p = L->next;//定义节点指针,指向首元节点
    while(p && p->data!=e){
        p=p->next;      //当前节点不是要找的,游标后移
    }
    return p;
}

//按值查找2
//在链表L中查找值为e的数据元素的位置序号
//若查找失败,返回 0
int LocateElem_index_L(LinkList L, ElemType e){
    LinkList p;
    p=L->next;      //定义指针p指向首元结点
    int j=1;        //声明计数器,保存所找位置序号
    while(p && p->data!=e){
        p=p->next;      //当前节点不符合,则游标后移
        j++;        //计数器加1
    }
    if(p != NULL){      //游标非空,表示在链表中找到了元素
        return j;       //返回所找元素位置序号
    }else{
        return 0;       //否则, 没找到目标元素
    }
}

//插入元素
//在第i个节点前插入值为e的新节点
//即:找到第 i-1 个节点,把待插入元素放到其后面
int ListInsert_L(LinkList &L, int i, ElemType e){
    Lnode *p= L;       //游标
    int j=0;        //计数器

    while(p != NULL && j<i-1){      //寻找第 i-1 个节点
        p=p->next;
        j++;
    }
    if(p==NULL){        //如果游标已经到了链表尾部(还没找到)
        return 0;       //定位失败,返回0
    }else{
        //游标p指向了第i-1个节点
        Lnode *newPoint = (LinkList)malloc(sizeof(Lnode));      //创建新节点
        newPoint->data = e;
        newPoint->next = p->next;
        p->next = newPoint;
        return 1;      //元素插入完毕,返回1
    }
}

//删除第i个节点
//首先定位到第i-1个节点
int ListDelete_L(LinkList &L, int i){
    LinkList p = L->next;   //游标指向首元节点
    int j=1;

    while(p!=NULL && j<i-1){
        p=p->next;      //游标后移
        j++;       //计数器自增
    }

    if(p->next == NULL || j>i-1){       //错误情况:要找的i大于链表的表长,游标移动到了链尾也找不到
        return 0;
    }

    //若已经定位到第i-1个节点处
    LinkList q = p->next;       //q指向第i个节点
    p->next = q->next;
    free(q);       //释放被删除节点的空间
    return 1;
}

//建立单链表:头插法
//头插法插入顺序是倒序的
/*
从一个空表开始,读入数据
生成新节点,将读入的数据放到新节点的数据域中
从后到前逐个将节点放到链表头部
*/
void CreateList_H(LinkList &L, ElemType e){
    Lnode *p;
    p = (LinkList)malloc(sizeof(Lnode));        //创建新节点
    p->data = e;
    p->next = NULL;

    //头插法核心代码
    p->next = L->next;
    L->next = p;
}

//尾插法
//一次插入一个节点
void CreateList_R(LinkList &L, ElemType e){      //&指引用型变量
    LinkList p = L;     //游标,先指向头节点
    LinkList newPoint = (LinkList)malloc(sizeof(Lnode));//建立新节点

    newPoint->data = e;
    newPoint->next = NULL;

    while(p->next != NULL){     //游标找到链表最后一个节点
        p=p->next;
    }
    p->next = newPoint;
}

//展示单链表
void DisList(LinkList L){
    Lnode *p = L->next;
    while(p!=NULL){
        printf("%c ", p->data);
        p=p->next;
    }
    printf("
");
}

//测试
void   testLinkList(){
    LinkList L;     //指向结构体的指针
    ElemType e;     //数据域
    printf("初始化单链表:
");
    InitList_L(L);

    printf("测试头插法插入 a,b,c,d
");
    CreateList_H(L, 'd');
    CreateList_H(L, 'c');
    CreateList_H(L, 'b');
    CreateList_H(L, 'a');

    printf("输出单链表:
");
    DisList(L);
    printf("表长:%d
", ListLength_L(L));

//    printf("测试尾插法插入:
");
//    CreateList_R(L, 'a');
//    CreateList_R(L, 'b');
//    CreateList_R(L, 'c');
//    CreateList_R(L, 'd');
//    printf("输出单链表:
");
//    DisList(L);
//    printf("表长:%d
", ListLength_L(L));

    printf("判断链表是否为空表:
");
    printf("%d
", ListEmpty(L));

    printf("清空链表:
");
    ClearList(L);
    printf("打印链表元素:
");
    DisList(L);
    printf("表长:%d
", ListLength_L(L));
    printf("判断链表是否为空表:
");
    printf("%d
", ListEmpty(L));

    printf("添加新元素:
");
    CreateList_H(L, 'o');
    CreateList_H(L, 'p');
    CreateList_H(L, 'q');
    CreateList_H(L, 'r');
    CreateList_H(L, 's');

    printf("销毁链表:
");
    DestroyList_L(L);
    printf("打印链表元素:
");
    DisList(L);
    printf("表长:%d
", ListLength_L(L));
    printf("判断链表是否为空表:
");
    printf("%d
", ListEmpty(L));


//    printf("查找第1个位置的值:%c
", GetElem_L(L, 1));
//    printf("查找第2个位置的值:%c
", GetElem_L(L, 2));
//    printf("查找第3个位置的值:%c
", GetElem_L(L, 3));
//    printf("查找第4个位置的值:%c
", GetElem_L(L, 4));
//    printf("查找第10个位置的值:%c
", GetElem_L(L, 10));

//    printf("查找a的位置:%d
", LocateElem_index_L(L, 'a'));
//    printf("查找b的位置:%d
", LocateElem_index_L(L, 'b'));
//    printf("查找c的位置:%d
", LocateElem_index_L(L, 'c'));
//    printf("查找d的位置:%d
", LocateElem_index_L(L, 'd'));

//        printf("在第3个元素前插入新元素'h',结果:%d
", ListInsert_L(L, 3, 'h'));
//        printf("打印链表:
");
//        DisList(L);
//
//        printf("在第10个元素前插入新元素'y',结果:%d
", ListInsert_L(L, 10, 'y'));
//        printf("打印链表:
");
//        DisList(L);
//
//        printf("删除第4个节点的元素:%d
", ListDelete_L(L, 4));
//        DisList(L);
}

测试结果:

原文地址:https://www.cnblogs.com/CPU-Easy/p/11707947.html