算法库应用- 表的自然链接

功  能: 设计算法,将两个单链表数组的特定位序, 相同者,链接起来
编程人: 王涛
详细博客:https://blog.csdn.net/qq_57484399/article/details/127161982
时  间: 2024.4.14

版本更新日志:

版  本1.0日志: V1.0 基本功能

版  本2.0日志  :  增加直接数组处理 , 无需人工输入, 增加数组数据遍历

目录

V1.0

main.cpp

v1.0运行结果:

V2.0

更新功能

main.cpp

v2.0运行结果:


V1.0

main.cpp

/*****************************************
功  能: 设计算法,将两个单链表数组的特定位序, 相同者,链接起来
编程人: 王涛
详细博客:https://blog.csdn.net/qq_57484399/article/details/127161982
时  间: 2024.4.14
版  本: V1.0
******************************************/
#include <stdio.h>
#include <malloc.h>

#define MaxCol 10

typedef int ElemType;

typedef struct dataNode
{
    ElemType date[MaxCol];  //存储数据的节点数组
    struct dataNode *next;     //定义节点的前驱指针
}DataList;

typedef struct headNode
{
    int row;    //头结点数据存储链表的 行数和列数
    int columns;
    DataList *next;  //头结点的后继指针类型是 DataList

}HeadList;


void CreatTable(HeadList *&new_table)
{
    int i,j;
    DataList *tailNode; //尾指针节点
    DataList *dataNode; //数据新节点
    new_table = (HeadList*)malloc(sizeof(HeadList));
    new_table->next = NULL;//基本头结点创建成功
    //下面分配行列数
    printf("请输入表的行数和列数:");
    scanf("%d%d",&new_table->row,&new_table->columns);
    //头结点基本创建完成

    //下面遍历输入数据节点
    for(i = 0;i < new_table->row; i++)
    {
        printf("请输入第%d行的数据:",i+1);
        //为每行数组分配空间
        dataNode = (DataList*)malloc(sizeof(DataList));
        for(j = 0;j < new_table->columns; j++)
        {
            scanf("%d",&dataNode->date[j]);
        }
        //数据填充完毕, 开始 尾插法插入头结点之后(head和data节点类型不一致,区分插入)
        if(new_table->next == NULL)
        {
            new_table->next = dataNode;
        }
        else
        {
            tailNode->next = dataNode;
        }
        tailNode = dataNode;    //尾结点指向新节点
    }
     //尾指针置空
    tailNode->next = NULL;
}
/*****************************************
    //定义指针指向数据节点

    //while(数据节点不为空){


        //()for循环遍历数组

        //遍历完指针后移
    //}
    //记得换行回车
******************************************/
void DisplayTable(HeadList *showTable)
{
    int i;
    //定义指针指向数据节点
    dataNode *nowNode = showTable->next;
    //while(数据节点不为空){
    printf("\n");
    while(nowNode != NULL)
    {
        //()for循环遍历数组
        for(i = 0; i < showTable->columns; i++)
        {
            printf("%2d",nowNode->date[i]);
            printf(" ");
        }
        //记得换行回车
        printf("\n");
        printf("\n");
        //遍历完指针后移
        nowNode = nowNode->next;
    }

}



void LinkTable(HeadList *first_table,HeadList *second_table,HeadList *&result_table)
{
    DataList *firstNode;
    DataList *secondNode;
    DataList *newNode;
    DataList *tailNode;
    int connect_table1,connect_table2;
    int serial_number;  //数组序号
    //result_table 头节点建立好 (列 = first_table->columns + second_table->columns),行不确定
    result_table = (HeadList*)malloc(sizeof(HeadList));
    result_table->columns = first_table->columns + second_table->columns;
    result_table->row = 0;  //目前是0
    //然后头结点next置空
    result_table->next = NULL;
    //while 遍历 first_table每个节点 ,
    firstNode = first_table->next;
    secondNode = second_table->next;

    printf("表1连接的数组位序:");
    scanf("%d",&connect_table1);
    getchar();getchar();
    printf("表2连接的数组位序:");
    scanf("%d",&connect_table2);

    while(firstNode != NULL)
    {
            secondNode = second_table->next;//每次都重新遍历
            //拿first_table一个节点 遍历 second_table的所有节点
            while(secondNode != NULL)
            {
                //判断特定行,特定列, 相等,则链接相关数组for循环
                if(secondNode->date[connect_table2-1] == firstNode->date[connect_table1-1])
                {
                    newNode = (DataList*)malloc(sizeof(DataList));
                    //连接两数组(first先, second后)
                    for(serial_number = 0; serial_number < first_table->columns;serial_number++)
                    {
                        newNode->date[serial_number] = firstNode->date[serial_number];
                    }
                    for(serial_number = 0;serial_number < second_table->columns;serial_number++)
                    {
                        newNode->date[(first_table->columns)+serial_number] = secondNode->date[serial_number];
                    }
                    if(result_table->next == NULL)
                    {
                        result_table->next = newNode;
                    }
                    else
                    {
                        tailNode->next = newNode;
                    }

                    tailNode =  newNode;
                    result_table->row++;
                    //尾插法插入result_table后
                }
                secondNode = secondNode->next;
            }
            firstNode = firstNode->next;
    }
    //result_table尾结点 置空
    tailNode->next = NULL;
}

int main()
{

    HeadList *first_table;  //代表要处理第一个表
    HeadList *second_table; //代表第要处理二个表
    HeadList *result_table;  //两个表处理后,存储结果的表C


    printf("表1:\n");
    //用头结点建表
    CreatTable(first_table);
    printf("表2:\n");
    //头结点建表
    CreatTable(second_table);

    //处理两个表
    LinkTable(first_table,second_table,result_table);


    DisplayTable(result_table);
    return 0;
}


v1.0运行结果:

V2.0

更新功能

方便手打数组:

ElemType first[5][3] = {
        {3,2,3},
        {2,1,2},
        {4,2,4},
        {1,1,2},
        {5,2,1},
};

ElemType second[4][2] = {
         {2,1},
         {1,2},
         {5,3},
         {2,4},
};

增加的功能: 计算 所写数组的 行,列, 并把数组填充到指针数组里面 , 方便弹性传入函数

 ephemeral_row =  sizeof(first)/sizeof(first[0]);
 ephemeral_columns =  sizeof(first[0])/sizeof(first[0][0]);


 ElemType **Array_use = (ElemType **)malloc(ephemeral_row*sizeof(ElemType*));
 for(int i = 0; i < ephemeral_row; i++)
 {
   Array_use[i] = (ElemType *)malloc(ephemeral_columns *sizeof(ElemType));
   //填充数据
   for(int j = 0; j < ephemeral_columns; j++)
   {
      Array_use[i][j] = first[i][j];
   }
 }

 CreatTable_auto(first_table,Array_use,ephemeral_row,ephemeral_columns);
  1. 计算行列数: 您已经使用了 sizeof 运算符来计算数组的行数和列数,这是正确的。这里是您的代码:

    ephemeral_row = sizeof(first) / sizeof(first[0]);
    ephemeral_columns = sizeof(first[0]) / sizeof(first[0][0]);
    
  2. 创建 CreatTable_auto 函数: 您需要修改 CreatTable_auto 函数,以便它可以接受一个指向指针的指针作为参数,这样就可以传入任意大小的二维数组。这里是修改后的函数原型:

    void CreatTable_auto(HeadList *&new_table, ElemType **Array_use, int row, int columns);
    
  3. 动态分配二维数组: 在调用 CreatTable_auto 之前,您需要动态创建一个二维数组。这里是如何做到这一点的示例代码:

    // 分配行指针
    ElemType **Array_use = (ElemType **)malloc(ephemeral_row * sizeof(ElemType *));
    for (int i = 0; i < ephemeral_row; i++) {
        // 为每一行分配列
        Array_use[i] = (ElemType *)malloc(ephemeral_columns * sizeof(ElemType));
        // 填充数据
        for (int j = 0; j < ephemeral_columns; j++) {
            Array_use[i][j] = first[i][j];
        }
    }

空间分配:

解析:

在C语言中,当您使用 malloc 动态分配内存来创建一个二维数组时,内存的摆放方式如下:

  1. 行指针数组: 首先,您分配了一个行指针数组。这个数组包含了指向每一行的指针。这些指针是有序的,按照您分配它们的顺序排列。例如,Array_use[0] 将指向第一行,Array_use[1] 将指向第二行,依此类推。

  2. 行内存分配: 对于每一行,您又分配了一个数组来存储实际的数据。这些数据数组也是有序的,每个数组对应于行指针数组中的一个指针。

这种内存摆放方式可以用以下图示表示:

Array_use --> [ Ptr_Row0 | Ptr_Row1 | Ptr_Row2 | ... | Ptr_RowN ]
                |           |           |               |
                v           v           v               v
              [Data_Row0] [Data_Row1] [Data_Row2] ... [Data_RowN]

每个 Ptr_RowX 是一个指针,指向一个 Data_RowX,这是一个包含行数据的数组。

当您需要访问这些行地址时,您可以直接通过行指针数组进行索引。例如,如果您想访问第 i 行的第 j 个元素,您可以使用 Array_use[i][j]。这是因为 Array_use[i] 给出了第 i 行的起始地址,而 [j] 给出了从该行起始地址开始的第 j 个元素的偏移量。

请注意,虽然这些行指针是连续存储的,但每一行的数据可能不是连续存储的。每一行都是单独分配的,所以它们在内存中的位置可能是分散的。

建表函数:

void CreatTable_auto(HeadList *&new_table,ElemType **Array_use,int row,int columns)
{
    int i,j;
    DataList *tailNode; //尾指针节点
    DataList *dataNode; //数据新节点
    new_table = (HeadList*)malloc(sizeof(HeadList));
    new_table->next = NULL;//基本头结点创建成功
    //下面分配行列数
    //计算行数
    new_table->row = row;//计算行数

    new_table->columns = columns;//计算行数

    //头结点基本创建完成

    //下面遍历输入数据节点
    for(i = 0;i < new_table->row; i++)
    {
//        printf("请输入第%d行的数据:",i+1);
        //为每行数组分配空间
        dataNode = (DataList*)malloc(sizeof(DataList));
        for(j = 0;j < new_table->columns; j++)
        {
//            scanf("%d",&dataNode->date[j]);
            dataNode->date[j] = Array_use[i][j];
        }

        //数据填充完毕, 开始 尾插法插入头结点之后(head和data节点类型不一致,区分插入)
        if(new_table->next == NULL)
        {
            new_table->next = dataNode;
        }
        else
        {
            tailNode->next = dataNode;
        }
        tailNode = dataNode;    //尾结点指向新节点
    }
     //尾指针置空
    tailNode->next = NULL;
}

解析: 因为使用的是 数组指针, 所以可以弹性访问数组内数据, 不在在意不同行和列

main.cpp

/*****************************************
功  能: 设计算法,将两个单链表数组的特定位序, 相同者,链接起来
编程人: 王涛
详细博客:https://blog.csdn.net/qq_57484399/article/details/127161982
时  间: 2024.4.14
v2.0日志:增设非交互模式
版  本: V2.0
******************************************/
#include <stdio.h>
#include <malloc.h>

#define MaxCol 10



typedef int ElemType;

typedef struct dataNode
{
    ElemType date[MaxCol];  //存储数据的节点数组
    struct dataNode *next;     //定义节点的前驱指针
}DataList;

typedef struct headNode
{
    int row;    //头结点数据存储链表的 行数和列数
    int columns;
    DataList *next;  //头结点的后继指针类型是 DataList

}HeadList;

ElemType first[5][3] = {
        {3,2,3},
        {2,1,2},
        {4,2,4},
        {1,1,2},
        {5,2,1},
};

ElemType second[4][2] = {
         {2,1},
         {1,2},
         {5,3},
         {2,4},
};


void CreatTable(HeadList *&new_table)
{
    int i,j;
    DataList *tailNode; //尾指针节点
    DataList *dataNode; //数据新节点
    new_table = (HeadList*)malloc(sizeof(HeadList));
    new_table->next = NULL;//基本头结点创建成功
    //下面分配行列数
    printf("请输入表的行数和列数:");
    scanf("%d%d",&new_table->row,&new_table->columns);
    //头结点基本创建完成

    //下面遍历输入数据节点
    for(i = 0;i < new_table->row; i++)
    {
        printf("请输入第%d行的数据:",i+1);
        //为每行数组分配空间
        dataNode = (DataList*)malloc(sizeof(DataList));
        for(j = 0;j < new_table->columns; j++)
        {
            scanf("%d",&dataNode->date[j]);
        }
        //数据填充完毕, 开始 尾插法插入头结点之后(head和data节点类型不一致,区分插入)
        if(new_table->next == NULL)
        {
            new_table->next = dataNode;
        }
        else
        {
            tailNode->next = dataNode;
        }
        tailNode = dataNode;    //尾结点指向新节点
    }
     //尾指针置空
    tailNode->next = NULL;
}


void CreatTable_auto(HeadList *&new_table,ElemType **Array_use,int row,int columns)
{
    int i,j;
    DataList *tailNode; //尾指针节点
    DataList *dataNode; //数据新节点
    new_table = (HeadList*)malloc(sizeof(HeadList));
    new_table->next = NULL;//基本头结点创建成功
    //下面分配行列数
    //计算行数
    new_table->row = row;//计算行数

    new_table->columns = columns;//计算行数

    //头结点基本创建完成

    //下面遍历输入数据节点
    for(i = 0;i < new_table->row; i++)
    {
//        printf("请输入第%d行的数据:",i+1);
        //为每行数组分配空间
        dataNode = (DataList*)malloc(sizeof(DataList));
        for(j = 0;j < new_table->columns; j++)
        {
//            scanf("%d",&dataNode->date[j]);
            dataNode->date[j] = Array_use[i][j];
        }

        //数据填充完毕, 开始 尾插法插入头结点之后(head和data节点类型不一致,区分插入)
        if(new_table->next == NULL)
        {
            new_table->next = dataNode;
        }
        else
        {
            tailNode->next = dataNode;
        }
        tailNode = dataNode;    //尾结点指向新节点
    }
     //尾指针置空
    tailNode->next = NULL;
}
/*****************************************
    //定义指针指向数据节点

    //while(数据节点不为空){


        //()for循环遍历数组

        //遍历完指针后移
    //}
    //记得换行回车
******************************************/
void DisplayTable(HeadList *showTable)
{
    int i;
    //定义指针指向数据节点
    dataNode *nowNode = showTable->next;
    //while(数据节点不为空){
    printf("\n");
    while(nowNode != NULL)
    {
        //()for循环遍历数组
        for(i = 0; i < showTable->columns; i++)
        {
            printf("%2d",nowNode->date[i]);
            printf(" ");
        }
        //记得换行回车
        printf("\n");
        printf("\n");
        //遍历完指针后移
        nowNode = nowNode->next;
    }

}



void LinkTable(HeadList *first_table,HeadList *second_table,HeadList *&result_table)
{
    DataList *firstNode;
    DataList *secondNode;
    DataList *newNode;
    DataList *tailNode;
    int connect_table1,connect_table2;
    int serial_number;  //数组序号
    //result_table 头节点建立好 (列 = first_table->columns + second_table->columns),行不确定
    result_table = (HeadList*)malloc(sizeof(HeadList));
    result_table->columns = first_table->columns + second_table->columns;
    result_table->row = 0;  //目前是0
    //然后头结点next置空
    result_table->next = NULL;
    //while 遍历 first_table每个节点 ,
    firstNode = first_table->next;
    secondNode = second_table->next;

    printf("表1连接的数组位序:");
    scanf("%d",&connect_table1);
    printf("表2连接的数组位序:");
    scanf("%d",&connect_table2);

    while(firstNode != NULL)
    {
            secondNode = second_table->next;//每次都重新遍历
            //拿first_table一个节点 遍历 second_table的所有节点
            while(secondNode != NULL)
            {
                //判断特定行,特定列, 相等,则链接相关数组for循环
                if(secondNode->date[connect_table2-1] == firstNode->date[connect_table1-1])
                {
                    newNode = (DataList*)malloc(sizeof(DataList));
                    //连接两数组(first先, second后)
                    for(serial_number = 0; serial_number < first_table->columns;serial_number++)
                    {
                        newNode->date[serial_number] = firstNode->date[serial_number];
                    }
                    for(serial_number = 0;serial_number < second_table->columns;serial_number++)
                    {
                        newNode->date[(first_table->columns)+serial_number] = secondNode->date[serial_number];
                    }
                    if(result_table->next == NULL)
                    {
                        result_table->next = newNode;
                    }
                    else
                    {
                        tailNode->next = newNode;
                    }

                    tailNode =  newNode;
                    result_table->row++;
                    //尾插法插入result_table后
                }
                secondNode = secondNode->next;
            }
            firstNode = firstNode->next;
    }
    //result_table尾结点 置空
    tailNode->next = NULL;
}

int main()
{

    HeadList *first_table;  //代表要处理第一个表
    HeadList *second_table; //代表第要处理二个表
    HeadList *result_table;  //两个表处理后,存储结果的表C
    int ephemeral_row;
    int ephemeral_columns;
    int mode;

    printf("请问您需要交互式,还是 直接处理数据呢? 1:交互  2:手写数组\n\n");
    scanf("%d",&mode);
    if(mode == 1)
    {
        printf("表1:\n");
        //用头结点建表
        CreatTable(first_table);
        printf("表2:\n");
        //头结点建表
        CreatTable(second_table);
    }
    else if(mode == 2)
    {
        ephemeral_row =  sizeof(first)/sizeof(first[0]);
        ephemeral_columns =  sizeof(first[0])/sizeof(first[0][0]);


        ElemType **Array_use = (ElemType **)malloc(ephemeral_row*sizeof(ElemType*));
        for(int i = 0; i < ephemeral_row; i++)
        {
            Array_use[i] = (ElemType *)malloc(ephemeral_columns *sizeof(ElemType));
            //填充数据
            for(int j = 0; j < ephemeral_columns; j++)
            {
                    Array_use[i][j] = first[i][j];
            }
        }

        CreatTable_auto(first_table,Array_use,ephemeral_row,ephemeral_columns);



        DisplayTable(first_table);
        ephemeral_row =  sizeof(second)/sizeof(second[0]);
        ephemeral_columns =  sizeof(second[0])/sizeof(second[0][0]);

        ElemType **Array_use1 = (ElemType **)malloc(ephemeral_row*sizeof(ElemType*));
        for(int i = 0; i < ephemeral_row; i++)
        {
            Array_use1[i] = (ElemType *)malloc(ephemeral_columns *sizeof(ElemType));
            //填充数据
            for(int j = 0; j < ephemeral_columns; j++)
            {
                    Array_use1[i][j] = second[i][j];
            }
        }

        CreatTable_auto(second_table,Array_use1,ephemeral_row,ephemeral_columns);
        DisplayTable(second_table);
    }

    //处理两个表
    LinkTable(first_table,second_table,result_table);

    printf("处理完后:\n\n");
    DisplayTable(result_table);
    return 0;
}

v2.0运行结果:

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值