[2020.10.14] 实现两个单向有序链表的合并

链表合并

http://www.nowcoder.com/questionTerminal/46bda7f0570a47b6b54a29a0a6ae4c27

递归方法

重做了一遍

  • 递归相对直观
  • 处理行输入用了stringstream,处理多余的空格,十分方便
  • 简化链表

后面迭代法可能有些说法错误,有部分多余,不过以下代码比较简单了。理解如何实现就行。

#include <iostream>
#include <string>
#include <sstream>

using std::cin;
using std::cout;
using std::endl;

using std::string;
using std::getline;
using std::stringstream;
using std::to_string;

// 链表
struct LinkedList {
  int value;
  LinkedList *next;

  LinkedList(int x): value(x), next(nullptr){}
};

void list_init(LinkedList *list, string s) {
  auto tmp = list;
  int x{0};
  stringstream ss(s);
  while (ss >> x) {
    tmp->next = new LinkedList(x);
    tmp = tmp->next;
  }
}

void list_print(const LinkedList *list) {
  string res{};
  auto tmp = list;
  while (tmp != nullptr) {
    res += to_string(tmp->value);
    if (tmp->next != nullptr) {
      res += " ";
    }
    tmp = tmp->next;
  }
  cout << res << endl;
}

LinkedList* merge(LinkedList *list1, LinkedList *list2) {
  if (list1 == nullptr) return list2;
  if (list2 == nullptr) return list1;

  if (list1->value < list2->value) {
    list1->next = merge(list1->next, list2);
    return list1;
  } else {
    list2->next = merge(list1, list2->next);
    return list2;
  }
}

int main(int argc, char **argv) {
  auto *list1 = new LinkedList(0);
  auto *list2 = new LinkedList(0);
  auto tmp = list1;

  string s;
  // get 数据
  getline(cin, s);
  list_init(list1, s);
  getline(cin, s);
  list_init(list2, s);

  auto res = merge(list1->next, list2->next);

  list_print(res);

  return 0;
}

初次做失误 -- 迭代方法可用

尝试用使用类,统一封装方法,这个代码有不少问题还是有很多问题:

  • 无法优雅处理链表的录入,违规输入没有报错机制;
  • 对空表直接判断,此处加了一个标志;
  • 写了节点相关的方法,但是create_nodeappend_node可以合并;
  • merge的处理仅仅考虑的数据,直接创建了新的链表使用,这个和就和作弊法差不多了。
  • 等等等

虽然很想完美处理,搞个通用的,太费时间了,能够解决问题就行;

核心代码:

下面展开给独立函数也是可以用的。

看了下题解,想法差不多;

  /**
连接有序节点
题目关键

遵守链表规则,修改next指向

有疑问,此处的链表可以为空吗
*/
  void sort_merge_list(LinkedList *linked_list) {
    // 处理空表
    if (this->is_empty && !linked_list->is_empty) {
      this->m_value = linked_list->m_value;
      this->next = linked_list->next;
      this->is_empty = false;

      return;
    }

    if (linked_list->is_empty) {
      return;
    }

    auto it = this;
    auto the = linked_list;

    auto *res = new LinkedList();

    // 标志
    bool has_node{false};
    int it_num{0}, the_num{0};
    // 比较
    while (it != nullptr || the != nullptr) {
      // 中转数字,用来记录大小的数字
      int tmp;
      it_num = it != nullptr ? it->m_value : it_num;
      the_num = the != nullptr ? the->m_value : the_num;

      // 判断
      // 此处到最后一个数字需要特殊处理,否则无法跳出循环
      if (it_num < the_num) {
    tmp = it_num;

    // 最终一个数字问题
    // 其中一个为nullptr的情况则进行置换
    if (it == nullptr && the != nullptr) {
      tmp = the_num;
      the = the->next;
    }
    it = it != nullptr ? it->next : it;
      } else {
    tmp = the_num;

    if (the == nullptr && it != nullptr) {
      tmp = it_num;
      it = it->next;
    }
    the = the != nullptr ? the->next : the;
      }

      // 加入内容
      if (!has_node) {
    res->create_node(tmp);
    has_node = true;
      } else {
    res->append_node(tmp);
      }
    }

    // 仅仅确保了数值相等
    // 头节点的地址发生了变化
    // 类创建链表 解决这个问题 有些麻烦
    this->m_value = res->m_value;
    this->next = res->next;
  }
};

完整代码:

#include <iostream>
#include <string>

using std::cin;
using std::cout;
using std::endl;

using std::string;
using std::getline;
using std::stoi;
using std::to_string;

// 无头节点
class LinkedList{
private:
  int m_value{0};
public:
  bool is_empty{true};

public:
  LinkedList *next{nullptr};

public:
  LinkedList() {};
  LinkedList(int value) {
    // 正常初始化
    this->create_node(value);

  }
  // 批量创建
  LinkedList(string values) {
    this->create_nodes(values);
  }

  ~LinkedList() {}

protected:
  /**
批量添加节点
string values 直接获取一行数据

TODO: 处理仅空格情况或者无输入
   */
  void create_nodes(string values) {
    // 转换字符串 手动
    string num_str{};
    int count{0};
    for (auto c : values) {
      if (isdigit(c)) {
    num_str += c;
      }
      if (isspace(c)) {
    int num = stoi(num_str);
    if (count++ != 0) {
      this->append_node(num);
    } else {
      this->create_node(num);
    }
    num_str = "";
      }
    }

    // 还有一个元素需要添加
    if (num_str == "") {
      return;
    }
    int num = stoi(num_str);
    if (count != 0) {
      this->append_node(num);
    } else {
      // 一个元素的情况
      this->create_node(num);
    }
  }

  /**
创建节点
*/
  void create_node(int value) {
    this->m_value = value;
    this->next = nullptr;
    this->is_empty = false;
  }

  /**
向后添加节点

该方法没有很好的处理错误,不暴露出去
*/
  void append_node(int value) {
    if (this->next == nullptr) {
      auto *new_node = new LinkedList(value);
      this->next = new_node;
    } else {
      this->next->append_node(value);
    }
  }

public:
  /**
打印节点
*/
  void print_nodes() {
    auto tmp = this;
    string res{};
    while (tmp->next != nullptr) {
      res += to_string(tmp->m_value);
      res += " ";
      // cout << tmp->m_value;
      tmp = tmp->next;
    }
    res += to_string(tmp->m_value);
    cout << res << endl;
  }

  /**
连接有序节点
题目关键

遵守链表规则,修改next指向

有疑问,此处的链表可以为空吗
*/
  void sort_merge_list(LinkedList *linked_list) {
    // 处理空表
    if (this->is_empty && !linked_list->is_empty) {
      this->m_value = linked_list->m_value;
      this->next = linked_list->next;
      this->is_empty = false;

      return;
    }

    if (linked_list->is_empty) {
      return;
    }

    auto it = this;
    auto the = linked_list;

    auto *res = new LinkedList();

    // 标志
    bool has_node{false};
    int it_num{0}, the_num{0};
    // 比较
    while (it != nullptr || the != nullptr) {
      // 中转数字,用来记录大小的数字
      int tmp;
      it_num = it != nullptr ? it->m_value : it_num;
      the_num = the != nullptr ? the->m_value : the_num;

      // 判断
      // 此处到最后一个数字需要特殊处理,否则无法跳出循环
      if (it_num < the_num) {
    tmp = it_num;

    // 最终一个数字问题
    // 其中一个为nullptr的情况则进行置换
    if (it == nullptr && the != nullptr) {
      tmp = the_num;
      the = the->next;
    }
    it = it != nullptr ? it->next : it;
      } else {
    tmp = the_num;

    if (the == nullptr && it != nullptr) {
      tmp = it_num;
      it = it->next;
    }
    the = the != nullptr ? the->next : the;
      }

      // 加入内容
      if (!has_node) {
    res->create_node(tmp);
    has_node = true;
      } else {
    res->append_node(tmp);
      }
    }

    // 仅仅确保了数值相等
    // 头节点的地址发生了变化
    // 类创建链表 解决这个问题 有些麻烦
    this->m_value = res->m_value;
    this->next = res->next;
  }
};

int main(int argc, char** argv)
{
  string list1{}, list2{};

  // cout << "链表1" << endl;
  getline(cin, list1);
  // cout << "链表2" << endl;
  getline(cin, list2);

  auto *linked_list1 = new LinkedList(list1);
  auto *linked_list2 = new LinkedList(list2);

  // linked_list1->print_nodes();
  // linked_list2->print_nodes();

  linked_list1->sort_merge_list(linked_list2);
  linked_list1->print_nodes();

  return 0;
}
全部评论

相关推荐

最近又搬回宿舍了,在工位坐不住,写一写秋招起伏不断的心态变化,也算对自己心态的一些思考表演式学习从开始为实习准备的时候就特别焦虑,楼主一开始选择的是cpp后端,但是24届这个方向已经炸了,同时自己又因为本科非92且非科班,所以感到机会更加迷茫。在某天晚上用java写出hello&nbsp;world并失眠一整晚后选择老本行干嵌入式。理想是美好的,现实情况是每天忙但又没有实质性进展,总是在配环境,调工具,顺带还要推科研。而这时候才发现自己一直在表演式学习,徘徊在设想如何展开工作的循环里,导致没有实质性进展。现在看来当时如果把精力专注在动手写而不是两只手端着看教程,基本功或许不会那么差。实习的焦虑5月,楼主...
耶比:哲学上有一个问题,玛丽的房间:玛丽知道眼睛识别色彩的原理知道各种颜色,但是她生活在黑白的房间里,直到有一天玛丽的房门打开了她亲眼看到了颜色,才知道什么是色彩。我现在最大可能的减少对非工作事情的思考,如果有一件事困扰了我, 能解决的我就直接做(去哪里或者和谁吵架等等……),解决不了的我就不想了,每一天都是最年轻的一天,珍惜今天吧
投递比亚迪等公司10个岗位 > 秋招被确诊为…… 牛客创作赏金赛
点赞 评论 收藏
分享
hso_:哈哈哈哈哈哈我没offer一样在同一道题开喷了
投递深圳同为数码等公司10个岗位
点赞 评论 收藏
分享
粗心的雪碧不放弃:纯学历问题,我这几个月也是一直优化自己的简历,后来发现优化到我自己都觉得牛逼的时候,发现面试数量也没有提升,真就纯学历问题
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务