潭影-pjq

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

单链表—线性表的链式存储结构实现(代码)

单链表—线性表的链式存储结构实现(代码)

单链表的操作还挺多的,代码也不少,注释写了很久,不过都明白了,明白了还是要忘记呀,所以要多复习

复制代码
#include<stdio.h>
#include<stdlib.h>
//以下操作均基于带头节点的单链表
//且我们把头节点视作第0个结点
typedef int    ElemType;
//定义单链表的结点类型
typedef struct LNode {   
    ElemType data;                      //定义结点的数据域
    struct LNode* next;                 //定义结点的指针域
}LNode,*LinkList;                       //为结构体起别名,前者突出是一个结点,后者突出一个单链表

//——————————————————————————————————————————————————————————————————————————————————————————————

//头插法新建链表        时间复杂度O(n)
LinkList List_HeadInsert(LinkList& L)
{
    int x;                              //需要插入的元素
    LNode* s;                           //定义一个结点,用于后续存放被插入元素的值
    L = (LinkList)malloc(sizeof(LNode));//申请一个空间,用于存放头结点(使用LinkList体现这是一个链表)
    L->next = NULL;                     //将头结点的指针域置空,因为目前单链表中尚无元素
    scanf("%d", &x);                    //读入元素
    while (x != 9999)                   //当读到9999表示停止读入
    {
        s = (LNode*)malloc(sizeof(LNode)); //申请一个新空间s用于存放需要插入的元素
        s->data = x;                       //将s的数据域置为x,即将x填入s的data域中
        s->next = L->next;                 //将s的指针域与L的指针域指向同一个空间
        L->next = s;                       //再将L的指针域指向s
        scanf("%d", &x);                   //继续读入元素
    }
    return L;                              //插入完毕返回头插法新建好的单链表
}
//尾插法新建链表        时间复杂度O(n)
LinkList List_TailInsert(LinkList& L)
{
    int x;                               //需要插入的元素
    L = (LinkList)malloc(sizeof(LNode)); //申请一个头节点(利用LinkList体现这是一个单链表)
    LNode* s, * r = L;                   //定义一个指针s用于存放需要插入的结点,定义一个尾指针r始终指向单链表尾部
    scanf("%d", &x);                     //读入元素
    while (x != 9999)                    //当读到9999时表示停止读入
    {
        s = (LNode*)malloc(sizeof(LNode));//申请一个新空间用于存放需要插入的元素
        s->data = x;                      //将s的指针域置为x
        r->next = s;                      //将r的指针域指向s,也就是说将头节点的指针域指向s
        r = s;                            //将r=s,即尾指针r始终指向单链表尾部
        scanf("%d", &x);                  //继续读入元素
    }
    r->next = NULL;            //所有元素插入完毕后,将尾指针置为空
    return L;                  //返回利用尾插法新建好的单链表
}

//——————————————————————————————————————————————————————————————————————————————————————————————

//按值查找             时间复杂度O(n)
LNode* LocateElem(LinkList L,ElemType e)//查找给定的一个值e,然后返回数据域为e的指针(利用LNode*体现返回的是结点)
{
    LNode* j;                           //新定义一个指针j
    j = L->next;                        //将j指向单链表的第一个元素
    while (j != NULL && j->data != e)   //从第一个结点开始查找数据域为e的结点
    {
        j = j->next;                    //没找到,j就指向下一个结点
    }
    return j;                           //找到了就跳出循环,并返回该结点的指针
}
//按位查找             时间复杂度O(n)
LNode* GetElem(LinkList L, ElemType i)//从单链表的第一个结点出发,顺指针next依序向后查找,直到找到第i个结点为止
{                                     //否则返回最后一个结点的指针域NULL
    int j = 1;                        //定义一个int型变量j,用于计数
    LNode* p = L->next;               //将p指向第一个结点
    if (i == 0)                       //如果i==0,表示查找的是头节点,
        return L;                     //就返回L(即头节点, 不过应该是一个奇怪的值,因为我们没有对头节点的数据域进行操作)
    if (i < 1)                        //即i为负值
        return NULL;                  //i无效,返回NULL
    while (p != NULL && j < i)        //从第一个结点开始找,找第i个结点
    {
        p = p->next;                  //没找到就将p指向下一个结点
        j++;                          //并且将j++                 
    }
    return p;                         //当j==i时,表示找到第i个结点,返回结点指针p   
}

//——————————————————————————————————————————————————————————————————————————————————————————————

//插入结点,按位序插入      时间复杂度O(n)
bool ListInsert(LinkList& L, int i, ElemType e)  //在单链表L中,第i个位置插入元素e
{
    if (i < 1)                                   //i<1,i无效
        return false;
    LNode* p;                                    //定义一个新结点p
    int j = 0;                                   //定义一个整型变量j,用于计数
    p = L;                                       //将p指向头结点
    while (p != NULL && j < i - 1)               //查找被插入位置之前的一个元素
    {
        p = p->next;                             //没找到p就指向下一个
        j++;                                     //并且将j++
    }
    if (p == NULL)                               //因为i值的不合法导致了p为空(eg:i超过了(表长+1))
        return false;
    LNode* s = (LNode*)malloc(sizeof(LNode));    //申请一个新空间s用于存放需要插入的元素
    s->data = e;                                 //这几步和头插法新建链表类似,不多赘述
    s->next = p->next;
    p->next = s;
    return true;                                 //插入成功
}
//指定结点的后插操作       时间复杂度O(n)
bool InsertNextNode(LNode* p, ElemType e)  
{                                          
    if (p == NULL)                         //如果p为空,即在在一个空间点后面插入元素,这显然是不正确的
        return false;
    LNode* s = (LNode*)malloc(sizeof(LNode)); //申请一个新空间用于存放需要插入的元素
    if (s == NULL)                            //这一步没什么用,是想说明申请空间可能会失败,
        return false;                         //即内存已满,无空闲空间
    s->data = e;                              //这几步和头插法新建链表类似,不多赘述
    s->next = p->next;
    p->next = s;
    return true;                              //插入成功
}
//指定结点的前插操作     时间复杂度O(1)   //在一个结点之前插入一个结点
bool InsertPriorNode(LNode* p, LNode* s)//因为单链表无法逆向检索,即不能知道前一个元素的值,
{                                       //只能通过next指针知道下一个结点的值,所以我们需要"偷天换日"
    if (p == NULL || s == NULL)         //如果指定结点或者需要插入的结点有一个为空,返回false
        return false;
    ElemType temp;                      //定义一个ElemType型变量(int型),用于暂存p的数据域
    s->next = p->next;                  //使s的指针域与指向的空间与p的指针域指向的空间相同
    p->next = s;                        //将s连在p之后
    temp = p->data;                     //将p的数据域中元素暂存到变量temp
    p->data = s->data;                  //将p的数据域中的元素修改为s的数据域中的元素
    s->data = temp;                     //将s的数据域中的元素修改位p的数据域中的元素,实现了p和s的数据域元素的交换(偷天换日)
    return true;                        //插入成功
}
//插入结点,按位序插入———利用函数封装
bool ListInsert2(LinkList& L, int i, ElemType e)
{
    if (i < 1)
        return false;
    LNode* p;
    int j = 0;
    p = L;
    while (p != NULL && j < i - 1)
    {
        p = p->next;
        j++;
    }
    InsertNextNode(p, e);
}

//——————————————————————————————————————————————————————————————————————————————————————————————

//按位序删除
bool ListDelete(LinkList& L, int i, ElemType& e)
{
    if (i < 1)                 //删除头结点是万万不行的
        return false;
    LNode* p;                  //定义一个新结点p
    p = L;                     //使得p等于头结点L
    int j = 0;                 //定义一个int型变量j
    while (p != NULL && j < i - 1)   //查找被删除元素前一个位置的元素
    {
        p = p->next;                 //没找到,p就指向下一个结点
        j++;                         //并且将j++
    }
    if (p == NULL)                   //i值不合法导致p为空(但是我没有看出来这一步的用处)
        return false;
    if (p->next == NULL)             //第i-1个结点之后已无其他结点
        return false;
    LNode* q = p->next;              //定义一个新指针q,令q指向被删除的节点
    e = q->data;                     //用e返回被删除元素的数据域的值
    p->next = q->next;               //将*q结点从单链表中断开
    free(q);                         //释放q结点
    return true;                     //删除成功
}
//指定结点的删除                     时间复杂度O(1) 
bool DeleteNode(LNode* p)           //删除一个指定结点p
{
    if (p == NULL)                  //p为空,删除失败(空结点,就不用删除了呗)
        return false;
    LNode* q = p->next;            //定义一个新指针q,并令其指向*q的后继结点   
    p->data = p->next->data;       //将结点p的数据域替换为结点q的数据域(此时p中存放的元素值为q中的元素值,即进行了替换)
    p->next = q->next;             //使得p的指针域指向的空间与q的指针域指向的空间相同(实现了将q从单链表中断开)
    free(q);                       //释放q
    return true;                   //删除成功
}

//——————————————————————————————————————————————————————————————————————————————————————————————

//求表长
ElemType Length(LinkList L)
{
    int len = 0;                 //定义一个int型变量len,将其置零
    LNode* j;                    //定义一个指针j,用于指向各个数据元素
    j = L->next;                 //将j指向第一个元素
    while (j != NULL)            
    {
        j = j->next;            //一直遍历到单链表的末尾
        len++;                  //将len++
    }
    return len;
}
//打印链表
void PrintList(LinkList L)
{
    LNode* j;
    j = L->next;
    while (j != NULL)
    {
        printf("%5d", j->data);
        j=j->next;
    }
    printf("\n");
}

//主函数
int main()
{
    LinkList L;
    LNode* p;
    ElemType e;
    int len;
    //List_HeadInsert(L);
    List_TailInsert(L);
    //1 2 3 4 5 6 7 8 9999
    //ListInsert(L, 7, 108);
    ListInsert2(L, 7, 108);
    ListDelete(L, 7, e);
    printf("被删除的元素是%d\n", e);
    PrintList(L);
    p=LocateElem(L, 3);
    printf("%3d", p->data);
    printf("\n");
    p = GetElem(L, 2);
    printf("%3d", p->data);
    printf("\n");
    len=Length(L);
    printf("表的长度为%d", len);
    return 0;
}
复制代码

 

posted on   潭影-pjq  阅读(85)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示