合并有序表 (顺序存储 和 链式存储 方式实现)

代码详细解析:

合并有序表文章浏览阅读1.4k次,点赞6次,收藏7次。●假设有两个有序表 LA和LB , 将他们合并成一个有序表LC●要求不破坏原有的表 LA和 LB构思:把这两个表, 合成一个有序表 , 不是简简单单吗?就算是把他们先遍历不按顺序插入到表 C里面 , 然后再排序 ,就行了,这个的确是最笨的办法 , 但是也能完成题目上 ,给出的是这两个表都是有序表 , 所以就省去了 ,我们遍历所有节点排序的麻烦 , 那我们也不能拿一个表进行强行插入, 题目上也不允许,_请设计一个能够将有序顺序表la,lb进行合并的算法,要求合并后的顺序表lc依然有序。https://blog.csdn.net/qq_57484399/article/details/127171775

版本更新日志

V1.0 : 顺序存储和链式存储, 初步利用算法库进行实现

目录

版本更新日志

V1.0

一 . 合并顺序存储有序表

 合并功能函数:

 用到的算法库:

list.h

list.cpp

main.cpp测试函数

运行演示结果:

二 . 合并链式存储有序表

合并功能函数:

用到的算法库:

singlelist.h

singlelist.cpp

main.cpp测试函数

运行结果演示:


V1.0

一 . 合并顺序存储有序表

 合并功能函数:

/**************************************************
函数名: Merged_ordered_list
功  能: 合并数组顺序表
参  数: SqList *LA,SqList *LB,SqList *&LC:把LA和LB合并成LC
注 意: ① 记得给LC长度赋值, 避免遍历时溢出
返回值:  无
**************************************************/
void Merged_ordered_list(SqList *LA, SqList *LB, SqList *&LC)
{
    int locationA = 0;
    int locationB = 0;
    int locationC = 0;
    LC = (SqList*)malloc(sizeof(SqList));
    //LA和LB均未达到末尾,选择小的加入
    while(locationA < LA->length && locationB < LB->length)
    {
        if(LA->data[locationA] < LB->data[locationB])
        {
            LC->data[locationC] = LA->data[locationA];
            locationA++;
            locationC++;
        }
        else
        {
            LC->data[locationC] = LB->data[locationB];
            locationB++;
            locationC++;
        }
    }
    //下面多两种情况其一或者没有
    //经过上一轮循环插入,LB已经扫描插入完了,
    //LA尚未扫描插入完,将LA其余元素插入到Lc中
    while(locationA < LA->length)
    {
        LC->data[locationC] = LA->data[locationA];
        locationA++;
        locationC++;
    }

    //经过上一轮循环插入,LA已经扫描插入完了,
    //LB尚未扫描插入完,将LB其余元素插入到LC中
    while(locationB < LB->length)
    {
        LC->data[locationC] = LB->data[locationB];
        locationB++;
        locationC++;
    }
    LC->length = locationC;   // ①
}

 用到的算法库:

list.h

#ifndef LIST_H_INCLUDE
#define LIST_H_INCLUDE


#include <malloc.h>

#define MaxSize   100

typedef int ElemType;	//自定义类型

typedef struct			//自定义结构体
{
	ElemType data[MaxSize];
	int length;
}SqList;

//①用数组创建线性表
void CreateList(SqList *&L, ElemType a[],int n);
//②初始化线性表
void InitList(SqList *&L);
//③输出线性表
void DispalyList(SqList *L);
//④判断是否为空表
bool ListEmpty(SqList *L);
//⑤销毁线性表
void DestroyList(SqList *&L);

//⑥ 求线性表的长度
int ListLength(SqList *L);

//⑦求某个位置的数据元素值GetElem(L,i,e)
bool GetElem(SqList *L,int i, ElemType &e);

//⑧ 元素 e 在 L中的序号(逻辑序号 1~n)
int LocateElement(ElemType element, SqList *L);

//⑨ L中 第 i 位, 插入 e, ListInsert(L,i,e)
bool ListInsert(SqList *&L,int i, ElemType e);

//⑩ 删除 L 中特定位置 i 的元素 e,  ListDelete(L,i,e)
bool ListDelete(SqList *&L, int i, ElemType &e);

#endif

list.cpp

#include <stdio.h>
#include "list.h"



/**************************************************
①函数名: CreateList
功  能: 用数组构建顺序表
参  数: ①SqList *&L:传入的线性表 ②ElemType a[]:使用的数组
		③int n: 线性表的长度(n < Maxsize)
返回值: 无
**************************************************/
void CreateList(SqList *&L, ElemType a[],int n)
{
	int i;
	//分配空间
	L = (SqList*)malloc(sizeof(SqList));
	for(i = 0; i<n; i++)
	{
		L->data[i] = a[i];
	}
	L->length = n;
}

/**************************************************
②函数名: InitList
功  能: 初始化线性表,重新分配空间,长度清成零
参  数: ①SqList *&L:要进行初始化的线性表
返回值:  无
**************************************************/

void InitList(SqList *&L)
{
	L = (SqList*)malloc(sizeof(SqList)); //既然初始化了,直接重新分配空间
	L->length = 0;

}


/**************************************************
③函数名: 		DispalyList
功  能: 	输出数组线性表到控制台
使用场景: 	调试输出专用
参  数: 	①SqList *L:所需展示的顺序表
返回值:		void
**************************************************/
void DispalyList(SqList *L)
{
	if(L->length == 0) return;
	for(int i = 0; i< L->length; i++)
	{
		printf("%d ",L->data[i]);
	}
	printf("\n");
}

/**************************************************
④函数名: 	ListEmpty
功  能: 判断顺序表是否为空
参  数: ① SqList *L: 需要判断的顺序表
返回值: (bool类型)  是空表 ? 返回1  : 不是返回0
**************************************************/
bool ListEmpty(SqList *L)
{
    return(L->length == 0);
}

/**************************************************
⑤函数名 : DestroyList
功  能: 释放顺序表空间
参  数: ① SqList *&L: 所需释放的线性表的指针地址
注  意: (1)
返回值:  无
**************************************************/
void DestroyList(SqList *&L) //(1)注意是指针地址
{
	//c语言, 直接free
	free(L);

}

/**************************************************
⑥函数名:ListLength
功  能: 返回顺序表长度
参  数: ① SqList *L:传入顺序表的名字
返回值:  int: 线性表长度值
**************************************************/
int ListLength(SqList *L)
{
    return (L->length);
}

/**************************************************
⑦函数名:GetElem
功  能: 取线性表数组内,某个序号的元素值,并返回
参  数: ①SqList *L: 要取的线性表 ②int i:要取的序号(逻辑需要 1-n)
        ③ElemType &e:返回到特定位置
注意:①合法性判断 ②   需要把逻辑(1~n)变成物理序号(0~n-1)
返回值:	bool:是否获取成功
**************************************************/
bool GetElem(SqList *L,int i, ElemType &e)
{
    if(i<1 || i>L->length)//①
    {
        return false;
    }
    e = L->data[i-1];  //②
    return true;
}

/**************************************************
⑧函数名: LocateElement
功  能: 查找特定元素值,在线性表中的位置(1~n)
参  数: ①ElemType element: 特定元素值 ② SqList *L:被查的线性表
返回值: int: 位置信息 (0没找到, 1~n, 即为位置)
**************************************************/
int LocateElement(ElemType element, SqList *L)
{
    int i = 0;
    while(i < L->length && L->data[i] != element) i++;
    //如果 i跳出后, i范围超过 L->length,则 没找到
    if(i >= L->length) return 0;
    else   return i+1;

}
/**************************************************
函数名: ListInsert
功  能: 把 e 插到到线性表 L 的第 i(逻辑序号) 个位置
参  数: (1)SqList *&L: 线性表L (2)int i: 插入到的逻辑位置
        (3) ElemType e:要插入的元素值
注意:① 可插入的位置逻辑序号为1~L->length+1
        ②得出 j最后是等于 i+1, 所以j的范围是 j>i
        ③从 j=L->length得出 , data[j] = data[j-1],从而确定整体范围
返回值: bool:是否插入完成
**************************************************/
bool ListInsert(SqList *&L,int i, ElemType e)
{
    int j;
    if(i<1 || i>L->length+1)    //①
        return false;
    i--;        //将顺序表的逻辑序号转化为物理序号
    for(j = L->length; j > i; j--)  //② data[i+1] = data[i] => j = i+1
    {
        //③ data[i]~data[L->length-1]整体后移到data[i+1]~data[L->length]
        L->data[j] = L->data[j-1];
    }
    L->data[i] = e;     //插入元素e
    L->length++;        //顺序表插入增1
    return true;       //成功插入返回true

}

/**************************************************
函数名: ListDelete
功  能: 删除顺序表特定位置的元素
参  数: (1)SqList *&L:被删的顺序表 (2)int i:位置
        (3)ElemType &e:删掉的值
注 意:  ① 思路是整体前移,所以确定初始值i,然后定公式,看临界定 范围
        ② 最后一个是 data[L->length-2] = data[L->length-1],
            得出 j = L->length-2
返回值: bool:是否删除成功? true : false
**************************************************/
bool ListDelete(SqList *&L, int i, ElemType &e)
{
    int j;
    if(i < 1 || i > L->length) return false;
    i--;    //把逻辑序号转为物理序号
    e = L->data[i]; //将要删除的元素存储
    for(j = i;j < L->length-1; j++)//①将data[i...n-1]整体前移
    {
    //② data[i+1]~data[L->length-1] => data[i] ~ data[L->length-2]
        L->data[j] = L->data[j+1];
    }
    L->length--;    //顺序表长度减去1
    return true;
}

main.cpp测试函数

#include "list.h"
#include "stdio.h"
/**************************************************
函数名: Merged_ordered_list
功  能: 合并数组顺序表
参  数: SqList *LA,SqList *LB,SqList *&LC:把LA和LB合并成LC
注 意: ① 记得给LC长度赋值, 避免遍历时溢出
返回值:  无
**************************************************/
void Merged_ordered_list(SqList *LA, SqList *LB, SqList *&LC)
{
    int locationA = 0;
    int locationB = 0;
    int locationC = 0;
    LC = (SqList*)malloc(sizeof(SqList));
    //LA和LB均未达到末尾,选择小的加入
    while(locationA < LA->length && locationB < LB->length)
    {
        if(LA->data[locationA] < LB->data[locationB])
        {
            LC->data[locationC] = LA->data[locationA];
            locationA++;
            locationC++;
        }
        else
        {
            LC->data[locationC] = LB->data[locationB];
            locationB++;
            locationC++;
        }
    }
    //下面多两种情况其一或者没有
    //经过上一轮循环插入,LB已经扫描插入完了,
    //LA尚未扫描插入完,将LA其余元素插入到Lc中
    while(locationA < LA->length)
    {
        LC->data[locationC] = LA->data[locationA];
        locationA++;
        locationC++;
    }

    //经过上一轮循环插入,LA已经扫描插入完了,
    //LB尚未扫描插入完,将LB其余元素插入到LC中
    while(locationB < LB->length)
    {
        LC->data[locationC] = LB->data[locationB];
        locationB++;
        locationC++;
    }
    LC->length = locationC;   // ①
}

int main()
{
    SqList *LA,*LB,*LC;
    ElemType A[3] = {1,3,5};
    ElemType B[4] = {2,4,8,10};

    CreateList(LA,A,3);
    printf("A展示:\n");
    DispalyList(LA);
    CreateList(LB,B,4);
    printf("B展示:\n");
    DispalyList(LB);

    printf("A+B合并排序成C展示:\n");
    Merged_ordered_list(LA,LB,LC);
    DispalyList(LC);

    return 0;
}

运行演示结果:

二 . 合并链式存储有序表

合并功能函数:

/**************************************************
函数名: Union_order_singlelist
功  能: 合并两个有序单链表为一个有序单链表
参  数: LinkList *LA,LinkList *LB, LinkList *&LC:LA和LB合并为LC
注  意: ①②③结束条件, 是遍历节点为空
返回值: 无
**************************************************/
void Union_order_singlelist(LinkList *LA,LinkList *LB, LinkList *&LC)
{
//    int counter = 0;
    //定义遍历LA和LB的指针
    LinkList *visit_A = LA->next;
    LinkList *visit_B = LB->next;
    //定位LC尾指针
    LinkList *tail_C;
    LinkList *newNode;
    //为LC头结点分配空间
    LC = (LinkList*)malloc(sizeof(LinkList));
    tail_C = LC;
    LC->next = NULL;

    //轮询遍历LA和LB,数据插入LC
    while(visit_A != NULL && visit_B != NULL) //①
    {
        //为LC新节点分配空间
        newNode = (LinkList*)malloc(sizeof(LinkList));
        if(visit_A->data < visit_B->data)
        {
            newNode->data = visit_A->data;
            //处理完后,后移,为后面做准备
            visit_A = visit_A->next;

            //对LC进行尾插法
            tail_C->next = newNode;
            tail_C = newNode;   //涉及指针覆盖,顺序不可调换
//            counter++;
//            printf("\n第%d个数是 %d \n",counter,newNode->data);

        }
        else
        {
            newNode->data = visit_B->data;
            //处理完后,后移,为后面做准备
            visit_B = visit_B->next;

            //对LC进行尾插法
            tail_C->next = newNode;
            tail_C = newNode;//涉及指针覆盖,顺序不可调换

//            counter++;
//            printf("\n第%d个数是 %d \n",counter,newNode->data);

        }

    }
	//经过上一步的交替插入,要么两个表交替插入完了,要么是下面两者之一
	//LB已经扫描插入完了, LA尚未扫描插入完 , 将其余元素插入到 Lc中
    while(visit_A != NULL)//③
    {
        //为LC新节点分配空间
        newNode = (LinkList*)malloc(sizeof(LinkList));

        newNode->data = visit_A->data;
        //处理完后,后移,为后面做准备
        visit_A = visit_A->next;

        //对LC进行尾插法
        tail_C->next = newNode;
        tail_C = newNode;   //涉及指针覆盖,顺序不可调换

//        counter++;
//        printf("\n第%d个数是 %d \n",counter,newNode->data);
    }

    while(visit_B != NULL) //③
    {
        //为LC新节点分配空间
        newNode = (LinkList*)malloc(sizeof(LinkList));
        newNode->data = visit_B->data;
        //处理完后,后移,为后面做准备
        visit_B = visit_B->next;
        //对LC进行尾插法
        tail_C->next = newNode;
        tail_C = newNode;//涉及指针覆盖,顺序不可调换
//        counter++;
//        printf("\n第%d个数是 %d \n",counter,newNode->data);
    }
    //尾结点置空,善后工作
    tail_C->next = NULL;
}

用到的算法库:

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);
}
/**************************************************
⑤函数名: 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"

/*****************************************
功  能: 把两个有序单链表合并成一个有序单链表
编程人: 王涛
时  间: 2024.4.16
版  本: V1.0
思路:
    //定义遍历LA和LB的指针
    //轮询遍历LA和LB,数据插入LC
    //收尾,LA或LB没遍历完,插入到LC
******************************************/

/**************************************************
函数名: Union_order_singlelist
功  能: 合并两个有序单链表为一个有序单链表
参  数: LinkList *LA,LinkList *LB, LinkList *&LC:LA和LB合并为LC
注  意: ①②③结束条件, 是遍历节点为空
返回值: 无
**************************************************/
void Union_order_singlelist(LinkList *LA,LinkList *LB, LinkList *&LC)
{
//    int counter = 0;
    //定义遍历LA和LB的指针
    LinkList *visit_A = LA->next;
    LinkList *visit_B = LB->next;
    //定位LC尾指针
    LinkList *tail_C;
    LinkList *newNode;
    //为LC头结点分配空间
    LC = (LinkList*)malloc(sizeof(LinkList));
    tail_C = LC;
    LC->next = NULL;

    //轮询遍历LA和LB,数据插入LC
    while(visit_A != NULL && visit_B != NULL) //①
    {
        //为LC新节点分配空间
        newNode = (LinkList*)malloc(sizeof(LinkList));
        if(visit_A->data < visit_B->data)
        {
            newNode->data = visit_A->data;
            //处理完后,后移,为后面做准备
            visit_A = visit_A->next;

            //对LC进行尾插法
            tail_C->next = newNode;
            tail_C = newNode;   //涉及指针覆盖,顺序不可调换
//            counter++;
//            printf("\n第%d个数是 %d \n",counter,newNode->data);

        }
        else
        {
            newNode->data = visit_B->data;
            //处理完后,后移,为后面做准备
            visit_B = visit_B->next;

            //对LC进行尾插法
            tail_C->next = newNode;
            tail_C = newNode;//涉及指针覆盖,顺序不可调换

//            counter++;
//            printf("\n第%d个数是 %d \n",counter,newNode->data);

        }

    }
	//经过上一步的交替插入,要么两个表交替插入完了,要么是下面两者之一
	//LB已经扫描插入完了, LA尚未扫描插入完 , 将其余元素插入到 Lc中
    while(visit_A != NULL)//③
    {
        //为LC新节点分配空间
        newNode = (LinkList*)malloc(sizeof(LinkList));

        newNode->data = visit_A->data;
        //处理完后,后移,为后面做准备
        visit_A = visit_A->next;

        //对LC进行尾插法
        tail_C->next = newNode;
        tail_C = newNode;   //涉及指针覆盖,顺序不可调换

//        counter++;
//        printf("\n第%d个数是 %d \n",counter,newNode->data);
    }

    while(visit_B != NULL) //③
    {
        //为LC新节点分配空间
        newNode = (LinkList*)malloc(sizeof(LinkList));
        newNode->data = visit_B->data;
        //处理完后,后移,为后面做准备
        visit_B = visit_B->next;
        //对LC进行尾插法
        tail_C->next = newNode;
        tail_C = newNode;//涉及指针覆盖,顺序不可调换
//        counter++;
//        printf("\n第%d个数是 %d \n",counter,newNode->data);
    }
    //尾结点置空,善后工作
    tail_C->next = NULL;
}

int main()
{
    LinkList *LA,*LB,*LC;
    //定义数组
    ElemType test_A[8] = {9,33,5,77,8,22,11,6};
    ElemType test_B[5] = {12,30,19,25,66};
    //尾插法建立单链表
    CreatList_Tail(LA,test_A,8);
    //输出展示
    printf("\nLA:\n");
    DisplayLinkList(LA);

    //把单链表变有序
    if(LinkList_sorting(LA))
    {
        printf("\n成功排序LA排序%d个数:\n",LinkListLength(LA));
        DisplayLinkList(LA);

    }

    CreatList_Tail(LB,test_B,5);
    printf("\nLB:\n");
    DisplayLinkList(LB);

    if(LinkList_sorting(LB))
    {
        printf("\n成功排序LB排序%d个数:\n",LinkListLength(LB));
        DisplayLinkList(LB);
    }

    Union_order_singlelist(LA,LB,LC);
    printf("\n成功合并LA和LB并排序%d个数为LC:\n",LinkListLength(LC));
    DisplayLinkList(LC);

    //释放空间
    DestroyLinkList(LA);
    DestroyLinkList(LB);
    DestroyLinkList(LC);


    return 0;
}

运行结果演示:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/549584.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

反转链表【java】

给定一个链表的头节点head反转链表 方法一&#xff1a;循环 1.定义三个指针&#xff1a; pre指针&#xff1a;刚开始指向空 prenull cur指针&#xff1a;刚开始指向head节点 curhead temp指针&#xff1a;保存cur指针指向节点的下一个节点 2. 不断循环改变相邻两个节点的指…

简约风好看的个人主页源码

效果图 PC端 移动端 源代码 index.html &#xfeff;<html lang"en"><head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&quo…

卷积神经网络的结构组成与解释(详细介绍)

文章目录 前言 1、卷积层 2、激活层 3、BN层 4、池化层 5、FC层&#xff08;全连接层&#xff09; 6、损失层 7、Dropout层 8、优化器 9、学习率 10、卷积神经网络的常见结构 前言 卷积神经网络是以卷积层为主的深层网络结构&#xff0c;网络结构包括有卷积层、激活层、BN层、…

大历史下的 tcp:从早期拥塞控制 到 bbr 再到未来

TCP协议有了拥塞控制机制&#xff0c;为什么还会网络拥塞&#xff1f; 随着骨干带宽增长&#xff0c;拥塞被阻滞在接入网&#xff0c;大规模拥塞崩溃难再呈现&#xff0c;tcp 拥塞控制(不仅限于 tcp&#xff0c;但以 tcp 为主线来说)从避免崩溃&#xff0c;保证可用性逐渐转到…

外包干了1年....字节跳动面试高频考点,懒加载

一、文章内容 什么是懒加载懒加载的优点什么时候使用懒加载学习懒加载前置内容实战懒加载图片 二、什么是懒加载? 从语法角度分析懒加载,懒是adj形容词,加载是名词;或者懒看为副词,加载作为动词,这样就能理解懒加载了就是懒懒的/地加载,更通俗的讲就是通过一种手段来加载.就…

java创建线程池的方法

简介 线程池是一种用于管理和重用线程的机制&#xff0c;它可以有效地管理线程的创建和销毁&#xff0c;减少线程创建和销毁的开销&#xff0c;并且能够控制并发线程数量&#xff0c;避免资源耗尽和系统过载。Java 提供了java.util.concurrent 包来支持线程池的实现。 1.Threa…

密码破解----zip文件密码字典、暴力破解

下边代码包含了暴力破解&#xff0c;使用字典破解zip的密码 from zipfile import ZipFile import os from tqdm import tqdm def passwd(path, pwd):# 获取文件的后缀名suffix_name os.path.splitext(path)[-1][1:]# print(suffix_name)# 如果是zip文件if suffix_name zip:#…

AIGC教育行业全景报告:AI助教和家教成真,学习机迎来新机遇

原文&#xff1a;AIGC教育行业全景报告&#xff1a;AI助教和家教成真&#xff0c;学习机迎来新机遇 - AI新智界 图片来源&#xff1a;由无界AI生成 经过一年的快速迭代&#xff0c;业内对于生成式AI将会率先落地于哪些行业已经有了答案。 教育领域&#xff0c;不仅被OpenAI列…

数字时代的风险评估:AI如何改变贷款分析

每样商品都有价格&#xff0c;但您能否负担得起&#xff1f;贷款非常适合生活中的大额支出&#xff0c;比如买房、买车或支付学费。偿还贷款可能会很棘手。根据最新的《家庭债务和信贷季度报告&#xff08;Quarterly Report on Household Debt and Credit&#xff09;》&#x…

2024年面试工具篇Postman面试题及答案

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

TypeScript之类

一、类的定义 二、对象的创建 class Person{id:number;name:string;age:number 18;constructor(id:number,name:string){this.id id;this.name name;}introduce():string{return hello,I am ${this.name},and I am ${this.age} years old.} }let person new Person(1,zhan…

Linux-docker安装数据库redis

1.拉取redis镜像 docker pull redis # 下载最新的redis版本 docker pull redis:版本号 # 下载指定的redis版本ps&#xff1a;我这是已经下载最新版本的redis 2.查看redis镜像 docker images3.创建挂在路径并授权 mkdir -p /usr/local/redis/data mkdir -p /usr/local…

Ubuntu22.04配置ROS2+PX4仿真环境

Ubuntu22.04配置ROS2PX4仿真环境 主要参考源&#xff1a; https://blog.csdn.net/weixin_44174421/article/details/135827130 https://blog.csdn.net/Zecet/article/details/130474620 一、准备工作 确保网络能够连接到github&#xff0c;出错主要源自于此&#xff1b;确保…

2024/4/16 网络编程day4

/*TCP并发服务器端*/ #include <myhead.h> #define SER_IP "192.168.125.173" #define SER_PORT 8888 void sighanger(int signum){if(signumSIGCHLD){//子进程终止信号while(waitpid(-1,NULL,WNOHANG)>0);//循环回收僵尸进程} }int main(int argc, const c…

03_信号和槽

信号和槽 系统的信号和槽自定义信号和槽Lambda表达式 系统的信号和槽 下面我们完成一个小功能&#xff0c;上面我们已经学习了按钮的创建&#xff0c;但是还没有体现出按钮的功能&#xff0c;按钮最大的功能也就是点击后触发一些事情&#xff0c;比如我们点击按钮&#xff0c;…

12.哀家要长脑子了!

1.189. 轮转数组 - 力扣&#xff08;LeetCode&#xff09; ​ 方法一&#xff1a; 要注意这个k是可以大于0的&#xff0c;所以旋转数组的时候要一直保证是在1-n的范围内&#xff1a;%实现 把k个元素旋转放到前面&#xff0c;前面n-k个元素是向后移动的。 class Solution { …

【Phytium】飞腾D2000 UEFI/EDK2 适配 RTC(IIC SD3077)

文章目录 0. env1. 软件2. 硬件 10. 需求1. 硬件2. 软件 20. DatasheetCPURTC 30. 调试步骤1. 硬件环境搭建2. UEFI 开发环境搭建3. 修改步骤1. UEFI 中使能RTC驱动、配置RTC信息等1.1 使能RTC驱动1.2 修改RTC对应的IIC配置信息1.3 解决驱动冲突1.4 验证波形 2. 修改对应RTC驱动…

[lesson36]经典问题解析三

经典问题解析三 关于赋值的疑问 什么时候需要重载赋值操作符&#xff1f;编译器是否提供默认的赋值操作&#xff1f; 编译器为每个类默认重载了赋值操作符 默认的赋值操作符仅完成浅拷贝 当需要进行深拷贝时必须重载赋值操作符 赋值操作符与拷贝构造函数有相同的存在意义 …

零基础入门测试该学什么?超全整理,照着学就对了!

对于很多小白而言&#xff0c;想要转行软件测试岗位&#xff0c;却又怕自己从来没有接触过计算机&#xff0c;底子很薄弱&#xff0c;从而还没开始就打起了退堂鼓。也有许多初学者&#xff0c;在入门的过程中&#xff0c;苦于不知道该学什么&#xff0c;又该从何学起&#xff0…

代码随想录算法训练营第四十二天| 二维背包、一维背包、LeetCode 416.分割等和子集

一、二维背包 文章讲解/视频讲解&#xff1a;https://programmercarl.com/%E8%83%8C%E5%8C%85%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%8001%E8%83%8C%E5%8C%85-1.html 状态&#xff1a;已解决 1.背包问题介绍 背包问题实则是一类问题的集合&#xff0c;有好多不同小类型&#xff0c…
最新文章