算法库应用-有序单链表插入节点

学习源头:

模仿贺利坚老师单链表排序文章浏览阅读5.9k次。  本文针对数据结构基础系列网络课程(2):线性表中第11课时单链表应用举例。例:拆分单链表 (linklist.h是单链表“算法库”中的头文件,详情单击链接…)//本程序严格讲有个bug,详见1楼#include <stdio.h>#include <malloc.h>#include "linklist.h"void split(LinkList *..._单链表生活例子https://blog.csdn.net/sxhelijian/article/details/48377185

构建单链表插入节点, 并保持有序单链表构造

本人解析博客:有序单链表插入节点文章浏览阅读1.3k次,点赞8次,收藏11次。跳出遍历的时候 , pre->next->data 大于等于新节点 ,那么 pre 指向的就是区间的左端点,pre->next指向的就是区间的右端点 ,按照上面的插入方法插入就可以了。当 pre 指向的节点的下一个节点比 新节点数值大 , 就跳出遍历,并且还要有下一个节点,没有的话,我们直接把新节点插入到尾结点就可以了。所以我们首先要找到这个区间, 然后 让 左端点的节点的后继指针指向 e , e的后继指针指向右端点就可以了。所以主要的问题是找到这个区间 ,然后让pre 指向区间的左端点 就行了。_实现单链表的有序插入。在一组有序的数中,从键盘输入一个元素值key,保证这组数仍https://blog.csdn.net/qq_57484399/article/details/127171275

更新版本日志:

V1.0 : 模仿老师,并构建增加 bool LinkList_sorting(LinkList *&L); 算法函数库,

基础上, 进行遍历对比,  插入节点, 保持有序构造

目录

更新版本日志:

V1.0:

功能函数 : ListInsert_orderly

使用构建函数库:

singlelist.h

singlelist.cpp

测试main.cpp

运行结果:

V1.0:

功能函数 : ListInsert_orderly

/**************************************************
函数名: ListInsert_orderly
功  能: 在一个有序链表的基础上,进行插入, 从而还是有序链表
参  数: (1)LinkList *&L:处理过的有序链表
        (2)ElemType insert_value:插入的元素

定义变量含义:
    (1)LinkList *preNode_Bigger:遍历找到最大节点的前一个节点,用来存储位置
    (2)LinkList *Bigger_Node:对比插入的最大节点,用来和插入值进行比较
    (3)LinkList *newNode: 插入构建的新节点
    (4)int counter:增加调试插入的位置

注 意:   ① 我们此时插入的是从小到大的有序表, 我们只需找到 最大节点的前一个节点即可
        ② preMaxNode只是遍历节点,刚开始是从小到大,直到遇到 插入节点 < 链表节点,
            我们把插入节点,放在链表节点前面
            这个是继续的条件, 结束的条件是
            preNode_Bigger->next == NULL 或者 insert_value < Bigger_Node->data
        ③不存在空,因为就算只有头结点, 我们直接插入preMaxNode后即可
        ④ 思路理清, preNode_Bigger是为了存储元素位置
                    Bigger_Node是为了方便对比元素值,避免混乱

返回值: 无
**************************************************/
void ListInsert_orderly(LinkList *&L, ElemType insert_value)
{
    LinkList *preNode_Bigger = L;   //①
    LinkList *Bigger_Node = preNode_Bigger->next;   //④
    LinkList *newNode;
    int counter = 0;
    while(preNode_Bigger->next != NULL && insert_value > Bigger_Node->data )//②
    {
        counter++;
        preNode_Bigger = preNode_Bigger->next;
        Bigger_Node = preNode_Bigger->next;
    }
    printf("\n %d 成功插入单链表,成为第 %d 个元素\n",insert_value,counter+1);

    //③
    newNode = (LinkList*)malloc(sizeof(LinkList));
    newNode->data = insert_value;    //构建新节点

    newNode->next = Bigger_Node;
    preNode_Bigger->next = newNode;//插入

}

使用构建函数库:

singlelist.h
#ifndef SINGLELIST_H_INCLUDE
#define SINGLELIST_H_INCLUDE

#include <stdio.h>
#include <malloc.h>

typedef int ElemType;   //定义单链表节点类型

typedef struct LNode
{
    ElemType data;
    struct LNode *next; //指向后继节点

}LinkList;
//①头插法建立单链表
void CreatList_Head(LinkList *&L, ElemType Array_used[], int Array_number);
//②尾插法建立单链表
void CreatList_Tail(LinkList *&L, ElemType Array_used[], int Array_number);
//③输出单链表
void DisplayLinkList(LinkList *L);
//④销毁单链表
void DestroyLinkList(LinkList *&L);
//⑤ 初始化线性表
void InitLinkList(LinkList *&L);
//⑥ 判断线性表是否为空表
bool LinkListEmpty(LinkList *L);
//⑦ 返回单链表L中数据节点的个数
int LinkListLength(LinkList *L);
//⑧ 求线性表L中指定位置的某个数据元素
bool SpecificLocate_Value(LinkList *L,int location, ElemType &value);
//⑨ 按元素值查找特定元素的位置
int SpecificValue_Location(LinkList *L, ElemType value);
//⑩ 把元素插入到特定位置
bool LinkList_InsertElement(LinkList *&L, int location, ElemType &value);
//(11) 删除特定位置的节点元素
bool LinkList_Delete_Location(LinkList *&L,int location, ElemType &value);
//(12)单链表删除其中其最大节点元素
bool  DeleteMaxNode(LinkList *&L);
//(13)对单链表中元素进行排序(至少有2个数据节点)
bool LinkList_sorting(LinkList *&L);
#endif // SINGLELIST_H_INCLUDE
singlelist.cpp
#include "singlelist.h"

/**************************************************
①函数名: CreatList_Head
功  能: 头插法建立单链表
参  数: (1)LinkList *&L: 传入的单链表指针地址
        (2)ElemType Array_used[]:要用来建表的数组
        (3)int Array_number: 数组的长度
返回值:    无
**************************************************/
void CreatList_Head(LinkList *&L, ElemType Array_used[], int Array_number)
{
    int counter;
    LinkList *newnode;
    L = (LinkList *)malloc(sizeof(LinkList)); //创建头结点
    L->next = NULL;
    for(counter = 0; counter < Array_number; counter++)
    {
        newnode = (LinkList *)malloc(sizeof(LinkList));  //创建新节点
        newnode->data = Array_used[counter];
        newnode->next = L->next;         //将newnode插在原开始结点之前,头结点之后
        L->next = newnode;
    }
}
/**************************************************
②函数名: CreatList_Tail
功  能: 尾插法建立单链表
参  数: (1)LinkList *&L: 传入的单链表指针地址
        (2)ElemType Array_used[]:要用来建表的数组
        (3)int Array_number:数组的长度
返回值:   无
**************************************************/
void CreatList_Tail(LinkList *&L, ElemType Array_used[], int Array_number)
{
    int counter;
    LinkList *newnode,*tailnode;
    L = (LinkList *)malloc(sizeof(LinkList));//创建头结点
    L->next = NULL;
    tailnode = L;       //尾结点tailnode始终指向终端结点,开始指向头结点
    for(counter = 0; counter < Array_number; counter++)
    {
        newnode = (LinkList *)malloc(sizeof(LinkList)); //创建新节点
        newnode->data = Array_used[counter];
        tailnode->next = newnode;   //将新节点插入到尾结点之后
        tailnode = newnode;         //更新尾结点
    }
    tailnode->next = NULL;          //终端结点next域置空
}

/**************************************************
③函数名: DisplayLinkList
功  能: 输出单链表
参  数: (1)LinkList *L:将要输出的单链表
返回值: 无
**************************************************/

void DisplayLinkList(LinkList *L)
{
    LinkList *shownode;
    shownode = L->next;
    while(shownode != NULL)
    {
        printf("%d",shownode->data);
        printf(" ");
        shownode = shownode->next;        //一直遍历,直到指向尾->newt = NULL
    }
    printf("\n");
}
/**************************************************
④函数名: DestroyLinkList
功  能: 销毁单链表
参  数: (1)LinkList *&L:要销毁的单链表
注意:① 等到指引下一个节点的指针为Null时就跳出,避免出现野指针,此时再销毁destroyNode
    ② 避免断开联系,记录 销毁节点的下一个节点
    ③避免空指针异常
返回值: 无
**************************************************/
void DestroyLinkList(LinkList *&L)
{
    LinkList *destoryNode,*nextNode;
    destoryNode = L;
    nextNode = destoryNode->next;

    while(nextNode != NULL)        //①
    {
        free(destoryNode);
        destoryNode = nextNode;
        nextNode = destoryNode->next;   //②
    }
    free(destoryNode);
    L->next = NULL;        //③
}
/**************************************************
⑤函数名: InitLinkList
功  能: 初始化单链表
参  数: LinkList *&L:要被初始化的链表指针地址
返回值: 无
**************************************************/
void InitLinkList(LinkList *&L)
{
    L = (LinkList *)malloc(sizeof(LinkList));//创建头结点
    L->next = NULL;
}
/**************************************************
⑥函数名: LinkListEmpty
功  能: 判断单链表是否为空
参  数: (1)LinkList *L:要判断的单链表
返回值: bool: 是否为空? treu:false
**************************************************/
bool LinkListEmpty(LinkList *L)
{
    return (L->next == NULL);
}

/**************************************************
⑦函数名: LinkListLength
功  能: 返回单链表L中数据节点的个数
参  数: LinkList *L:要计算的数据节点
返回值: int: 线性表数据节点个数值
**************************************************/
int LinkListLength(LinkList *L)
{
    int counter = 0;
    LinkList *nowNode = L;
    while(nowNode->next != NULL)
    {
        counter++;
        nowNode = nowNode->next;
    }
    return counter;
}

/**************************************************
⑧函数名: GetLocateValue
功  能: 求特定位置的数据元素值
参  数: (1)LinkList *L:要找的单链表
        (2)int location:所要找的位置
        (3)ElemType &value: 传递回所要找的值
注意: ① 判断跳出的时候, 是查找成功, 还是抵达末尾
     ② counter == 要找到序号,则跳出,所以counter < location  ,
    nowNode指向的节点为空,则到末尾,则跳出
    ③④ 这两条语句, 所指向的序号和节点, 是同步的, 位置到或者此节点为空,则跳出
返回值: bool: 是否查找成功? true:false
**************************************************/
bool SpecificLocate_Value(LinkList *L,int location, ElemType &value)
{
    int counter = 0;
    LinkList *nowNode = L;
    while(counter < location && nowNode != NULL)//②
    {
        counter++;          //③  当前计数的节点
        nowNode = nowNode->next;//④当前遍历到的节点
    }
    if(nowNode == NULL)                //①
    {
        return false;
    }
    else
    {
        value = nowNode->data;
        return true;
    }

}

/**************************************************
⑨函数名:SpecificValue_Location
功  能: 查找特定数据值的节点,并返回其位置
参  数: (1)LinkList *L: 被查找的单链表(2)ElemType e:
注  意:  ①从头结点后的第一个节点开始找
         ②while循环内的两条语句是同步指向的
         ③当nowNode为空时(到达末尾仍未找到), counter作废
         ④当nowNode不为空时,跳出时, counter表示所指向节点存在,并符合所需
返回值:
**************************************************/
int SpecificValue_Location(LinkList *L, ElemType value)
{
    int counter = 1;
    LinkList *nowNode = L->next;    //①
    while(nowNode != NULL && nowNode->data != value)
    {
        nowNode = nowNode->next;
        counter++;                     //②
    }
    if(nowNode == NULL)           //③
    {
        return 0;
    }
    else                    //④
    {
        return counter;
    }

}
/**************************************************
⑩函数名: LinkList_InsertElement
功  能: 在单链表特定位置插入节点
参  数: (1)LinkList *&L:要插入的单链表
        (2)int location:要插入的位置
        (3) ElemType &value:插入的数据
思路:    先在单链表L中,找到第 i-1个节点(不算头结点),若存在这样的节点,
        将值为value的节点 插入到其后面
注意:    ① 计数器和 nowNode是同步往后移动(从L->next开始算第一个节点),
         直到 找到counter = location-1,
         ②此时 nowNode不为空,则此时nowNode指向
         要插入位置的 前一个节点
         ③ 覆盖指针前, 牢记 nowNode->next里面存放的是后继节点信息,所以要先处理
          newNode->next = nowNode->next;
          然后我们才能再把 nowNode->next指向新节点 newNode
返回值: bool: 是否存在第i-1个节点,并插入成功? true : false
**************************************************/
bool LinkList_InsertElement(LinkList *&L, int location, ElemType &value)
{
        int counter = 0;
        LinkList *nowNode = L;
        LinkList *newNode;
        while((counter < (location-1)) && (nowNode != NULL)) //①
        {
            counter++;
            nowNode = nowNode->next;
        }
        if(nowNode == NULL)//②
        {
            return false;
        }
        else
        {
            newNode = (LinkList *)malloc(sizeof(LinkList));
            newNode->data = value;
            newNode->next = nowNode->next;//③
            nowNode->next = newNode;
            return true;
        }
}
/**************************************************
(11)函数名: LinkList_Delete_Location
功  能: 删除特定位置的节点元素
参  数: (1)LinkList *&L:被删除的单链表 (2)int location:特定位置
        (3) ElemType &value:被删除的元素值
思路:    找到第location-1个元素, 存储第locataion个元素值(判断null),然后free
        链接 location-1 和 location+1
注意:    ① counter和指针节点是同步的,要么找到location-1个节点,要么到末尾
        ② 虽然可能找到location-1个元素,其可能是最后一个元素,从而导致删除失败
        需要判断一下,deleteNode是否为空,才能得出是否任务成功
        ③ 指针覆盖还是老生常谈,先存储一下deleteNode(方便free),
           然后指针交替,然后free
返回值:  bool: 是否删除成功? true:false
**************************************************/
bool LinkList_Delete_Location(LinkList *&L,int location, ElemType &value)
{
    int counter = 0;
    LinkList *nowNode = L;
    LinkList *deleteNode;
    while(counter < (location-1) && nowNode != NULL)   //①
    {
        counter++;
        nowNode = nowNode->next;
    }
    if(nowNode == NULL)
    {
        return false;
    }
    else
    {
        deleteNode = nowNode->next;
        if(deleteNode == NULL)    //②
        {
            return false;
        }
        value = deleteNode->data;
        nowNode->next = deleteNode->next;  //③
        free(deleteNode);
        return true;
    }
}

/**************************************************
(12)函数名: DeleteMaxNode
功  能: 删除单链表中最大的一个节点
参  数: (1)LinkList *&L:要删除节点的单链表
思路: 四个指针, 最大指针,最大指针前一个节点
    目前遍历的指针,遍历指针的前一个节点, 边比较,边替换,边遍历
注意:①避免只有一个头结点,造成空指针替换异常
    ②③ 顺序不能变,因为③跳出的时候, 会利用到while的非空条件,
   避免对比的时候, 出现野指针,直到为空时,即可直接跳出,非空则比较替换
返回值:是否删除成功 ? true:false
**************************************************/
bool   DeleteMaxNode(LinkList *&L)
{
    LinkList *nowNode,*preNode;
    LinkList *maxNode,*preMaxNode;
    nowNode = L->next;
    preNode = L;
    maxNode = nowNode;
    preMaxNode = preNode;
    if(nowNode == NULL) //①
    {
        return false;
    }
    while(nowNode != NULL) //直到末尾
    {
        if(nowNode->data > maxNode->data)   //②
        {
            maxNode = nowNode;
            preMaxNode = preNode;
        }
        preNode = nowNode;       //接着走下一个节点
        nowNode = nowNode->next;   //③
    }
    preMaxNode->next = maxNode->next;
    free(maxNode);
    return true;
}

/**************************************************
(13)函数名:LinkList_sorting
功  能:对单链表中元素进行排序(至少有2个数据节点)
参  数:LinkList *&L:要进行排序的单链表
注意: ① 空表,或者只有一个数据节点,则不需要排序,返回false
      ② 开始节点必须是头结点,因为我们会用到start_compare->next,
      ③ 把数据节点(第二个数据节点及以后)和原始链表(头结点+一个数据节点)
      ④ 在有序表中,一直找到比前一个节点大,比后一个节点小的空挡,
         所以时刻对比start_compare->next->data, 并且start_compare->next不能为空
         (为空代表到达末尾,交替空指针)
        ⑤ 顺序不能变, 避免丢失有序表后续信息(指针覆盖的一句话)
详细链接:https://blog.csdn.net/qq_57484399/article/details/127141307
返回值:bool: 是否符合排序标准,并排序成功  ? true: false
**************************************************/
bool LinkList_sorting(LinkList *&L)
{
    LinkList *compare,*start_compare,*Remaining_node;
    if(L->next == NULL || L->next->next == NULL)//①保证至少有2个数据节点
    {
        return false;
    }
    compare = L->next->next;
    start_compare = L;  //②开始节点必须是头结点
    Remaining_node = compare->next;
    L->next->next = NULL; //③把数据节点(第二个数据节点及以后)和原始链表(头结点+一个数据节点)

    while(compare != NULL)
    {
        Remaining_node = compare->next;
        start_compare = L;
        while((start_compare->next != NULL) && (compare->data > start_compare->next->data))
        {
            start_compare = start_compare->next;
        } //④

        compare->next = start_compare->next;
        start_compare->next = compare;     //⑤
        compare = Remaining_node;
    }
    return true;

}
测试main.cpp
#include <stdio.h>
#include "singlelist.h"


/**************************************************
函数名: ListInsert_orderly
功  能: 在一个有序链表的基础上,进行插入, 从而还是有序链表
参  数: (1)LinkList *&L:处理过的有序链表
        (2)ElemType insert_value:插入的元素

定义变量含义:
    (1)LinkList *preNode_Bigger:遍历找到最大节点的前一个节点,用来存储位置
    (2)LinkList *Bigger_Node:对比插入的最大节点,用来和插入值进行比较
    (3)LinkList *newNode: 插入构建的新节点
    (4)int counter:增加调试插入的位置

注 意:   ① 我们此时插入的是从小到大的有序表, 我们只需找到 最大节点的前一个节点即可
        ② preMaxNode只是遍历节点,刚开始是从小到大,直到遇到 插入节点 < 链表节点,
            我们把插入节点,放在链表节点前面
            这个是继续的条件, 结束的条件是
            preNode_Bigger->next == NULL 或者 insert_value < Bigger_Node->data
        ③不存在空,因为就算只有头结点, 我们直接插入preMaxNode后即可
        ④ 思路理清, preNode_Bigger是为了存储元素位置
                    Bigger_Node是为了方便对比元素值,避免混乱

返回值: 无
**************************************************/
void ListInsert_orderly(LinkList *&L, ElemType insert_value)
{
    LinkList *preNode_Bigger = L;   //①
    LinkList *Bigger_Node = preNode_Bigger->next;   //④
    LinkList *newNode;
    int counter = 0;
    while(preNode_Bigger->next != NULL && insert_value > Bigger_Node->data )//②
    {
        counter++;
        preNode_Bigger = preNode_Bigger->next;
        Bigger_Node = preNode_Bigger->next;
    }
    printf("\n %d 成功插入单链表,成为第 %d 个元素\n",insert_value,counter+1);

    //③
    newNode = (LinkList*)malloc(sizeof(LinkList));
    newNode->data = insert_value;    //构建新节点

    newNode->next = Bigger_Node;
    preNode_Bigger->next = newNode;//插入

}

int main()
{
    LinkList *A;
    //定义数组
    ElemType test_array[] = {9,3,5,7,8,2,1,6};
    //尾插法建立单链表
    CreatList_Tail(A,test_array,8);
    //输出展示
    DisplayLinkList(A);
    //把单链表变有序
    if(LinkList_sorting(A))
    {
        printf("排序成功!\n");
    }
    //输出展示
    DisplayLinkList(A);
    //再在此基础上, 添加元素, 时钟保持有序链表(输出,插入到了第几个位置)
    ListInsert_orderly(A,4);
    //输出展示
    DisplayLinkList(A);
    //销毁,释放空间
    DestroyLinkList(A);
    if(LinkListEmpty(A))
    {
        printf("\n成功销毁单链表A\n");
    }
    printf("\nA销毁后长度 %d \n",LinkListLength(A));

    return 0;
}
运行结果:

  • 35
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值