手把手教数据结构与算法:有序线性表设计(表合并)

个人主页:

想转码的电筒人

专栏:

手把手教数据结构与算法

文章目录

有序线性表

概念

结构

问题描述

输入

输出

样例

解题步骤

结点类

链表类

insert函数

printAll函数

merge函数

test函数

完整代码


有序线性表

概念

单链表是一种物理存储结构上非连续、非顺序的存储结构,但链表在逻辑上是连续的,顺序的,而数据元素的逻辑顺序是通过链表中的指针连接次序实现的。

结构

单链表是由一个个结点组成的,结点如下图所示:

注意:单链表中的最后一个结点的next指向空,next=NULL,一个个结点串联组成了链表。

上图是为了方便大家理解,才用线条连接了结点,实际上在内存中,每个结点可能会隔得很远,每个结点右半部分就是这个结点的地址,很明显能看到这两个结点的地址并不是相邻的,因此也验证了顺序表在逻辑结构上确实是连续的,但在物理存储结构上确实是不连续的。

链表的基本操作

1.插入操作(Insert): 在指定节点之后插入新节点

2.删除操作(Delete): 删除指定位置的节点

3.访问操作(Access):获取链表中指定位置的节点值

4.获取长度(GetLength):获取链表的长度

5.搜索操作(Search): 判断链表中是否包含指定的值,搜索指定值在链表中的位置(索引)。

6.其他操作

反转链表(Reverse):将链表中的节点顺序颠倒过来。

合并链表(MergeLists):将两个链表合并成一个链表。

切分链表(SplitList):将链表从指定位置切分成两个链表。

环检测(HasCycle):检测链表中是否存在环。 找出链表中点(FindMiddle):返回链表的中间节点

有序线性表(Ordered Linear List)也是一种链表,其中的元素按照某种顺序排列。通常,这种顺序是指元素按照某个关键字的大小进行排序,下面让我们一起实现它。

问题描述

设计一个有序线性表类,要求完成初始化,插入和遍历功能,使得表内元素实现有序排列(从小到大)。同时实现合并功能,使得两个线性表能够合并为一个线性表(可能存在重复元素)。

  • 要求使用链表和泛型编程。
  • 注:不要忘了回收指针。
输入

第一行输入字符串 dtype(“int”或者”float”)表示数据存储类型。
第二行输入 int 型数据 N1(N1≥0),代表第一个线性表元素数量;
第三行输入 N1 个 dtype 型数据,每个数据由空格隔开;
第四行输入 int 型数据 N2(N2≥0),代表第二个线性表元素数量;
第五行输入 N2 个 dtype 型数据,每个数据由空格隔开;

输出

遍历第一个线性表,第一行输出其遍历结果,每个数据由空格隔开。
遍历第二个线性表,第二行输出其遍历结果,每个数据由空格隔开。
第三行输出第一个线性表和第二个线性表合并后的遍历结果,每个数据由空格隔开。

  • 注:线性表为空时仅输出换行符,每行输出的末尾没有空格。
样例

输入:

int
7 15 24 0 13 7 15 8
3 15 1 2

输出:

0 7 8 13 15 15 24
1 2 15
0 1 2 7 8 13 15 15 15 24

解题步骤

结点类

首先是链表的结点设计,可以设计出结构体 Node 表示结点,其中包含有 data 域和 next 指针,如下图:


其中 data 表示数据,其可以是简单的类型,也可以是复杂的结构体,故采用泛型编程template<typename T>。next 指针表示,下一个的指针,其指向下一个结点,通过 next 指针将各个结点链接。结点类还有构造函数,在创建结点时可以进行初始化,

template <typename T>
struct Node
{
    Node* next;
    T value;
};
链表类

链表只需要头指针用来指向链表的起点,构造函数只需让head指向空结点,析构函数则用来删除链表中所有的结点

class List
{
public:
    Node<T>* head;
    List() : head(nullptr) {
        head = new Node<T>;
        head->next = nullptr;
    };
    ~List()
    {
        Node<T>* p;
        while (head != nullptr)
        {
            p = head;
            head = head->next;
            delete p;
        }
    }
};
insert函数

向队列中插入一个节点,值为value,使得表内元素实现有序排列(从小到大)

在链表中插入结点时,若链表为空,则将该新结点作为空结点,若链表不为空,题目要求该链表为有序线性表,故需要先通过比较新插入的结点值与链表结点值,找到结点插入的位置再进行插入

void insert(T value)
{
    Node<T>* p = head;              //获得头节点指针    
    Node<T>* node = new Node<T>;    //创建新的节点
    node->value = value;
    node->next = nullptr;
    Node<T>* tem = head;
    if (p == nullptr) p->value = value;
    for (; p != nullptr;)
    {
        if (node->value > p->value)
        {
            tem = p;
            p = p->next;
        }
        else
        {
            node->next = tem->next;
            tem->next = node;
            break;
        }
    }
    if (tem && tem->next != node)
    {
        tem->next = node;
    }
}
printAll函数

遍历并输出线性表

从头指针开始遍历即可。通过一个指针从链表的第一个元素开始,依次遍历每个节点,并输出节点的值。最终在打印完成后输出换行符。

void printAll()
    /*
    函数名:printAll
    输入值:无
    功  能:遍历并输出线性表
     */
{
    Node<T>* p = head->next;
    if (p == nullptr)
    {
        cout << endl;
        return;
    }
    for (; p->next != nullptr;)
    {
        cout << p->value << " ";
        p = p->next;
    }
    cout << p->value;
    cout << endl;
}
merge函数

合并两个线性表

遍历线性表2,使用insert函数将表2的结点插入表1,即可实现表1和表2的合并

void merge(List<T>* l2)
{
    Node<T>* p = l2->head->next;
    for (; p != nullptr;)
    {
        insert(p->value);
        p = p->next;
    }
}
test函数

调用链表函数完成题目要求

void test()
{
    int N1, N2;
    T value;
    List<T> l1, l2;
    cin >> N1;
    for (; N1 > 0; N1--)
    {
        cin >> value;
        l1.insert(value);
    }
    l1.printAll();
    cin >> N2;
    for (; N2 > 0; N2--)
    {
        cin >> value;
        l2.insert(value);
    }
    l2.printAll();
    l1.merge(&l2);
    l1.printAll();
}

完整代码

#include <iostream>
using namespace std;
template <typename T>
struct Node
{
    Node* next;
    T value;
};
template <typename T>
class List
{
public:
    Node<T>* head;
    List() : head(nullptr) {
        head = new Node<T>;
        head->next = nullptr;
    };
    ~List()
    {
        Node<T>* p;
        while (head != nullptr)
        {
            p = head;
            head = head->next;
            delete p;
        }
    }

    void insert(T value)
     
    {
        Node<T>* p = head;              //获得头节点指针    
        Node<T>* node = new Node<T>;    //创建新的节点
        node->value = value;
        node->next = nullptr;
        Node<T>* tem = head;
        if (p == nullptr) p->value = value;
        for (; p != nullptr;)
        {
            if (node->value > p->value)
            {
                tem = p;
                p = p->next;
            }
            else
            {
                node->next = tem->next;
                tem->next = node;
                break;
            }
        }
        if (tem && tem->next != node)
        {
            tem->next = node;
        }
    }

    void printAll()
     
    {
        Node<T>* p = head->next;
        if (p == nullptr)
        {
            cout << endl;
            return;
        }
        for (; p->next != nullptr;)
        {
            cout << p->value << " ";
            p = p->next;
        }
        cout << p->value;
        cout << endl;
    }

    void merge(List<T>* l2)
        
    {
        Node<T>* p = l2->head->next;
        for (; p != nullptr;)
        {
            insert(p->value);
            p = p->next;
        }
    }
};
template <typename T>
void test()
{
    int N1, N2;
    T value;
    List<T> l1, l2;
    cin >> N1;
    for (; N1 > 0; N1--)
    {
        cin >> value;
        l1.insert(value);
    }
    l1.printAll();
    cin >> N2;
    for (; N2 > 0; N2--)
    {
        cin >> value;
        l2.insert(value);
    }
    l2.printAll();
    l1.merge(&l2);
    l1.printAll();
}
int main()
{
    string dtype;
    cin >> dtype;
    if (dtype == "int")
        test<int>();
    else
        test<float>();
    return 0;
}

  • 180
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 146
    评论
评论 146
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值