C++ 如何创建单词阶梯?
我正在尝试创建一个单词阶梯,使用一个链接列表作为单词字典,并使用一个队列来保存要更改的单词 在队列的C++ 如何创建单词阶梯?,c++,linked-list,queue,C++,Linked List,Queue,我正在尝试创建一个单词阶梯,使用一个链接列表作为单词字典,并使用一个队列来保存要更改的单词 在队列的while循环中,它到达字典中的第一个单词(单词“toon”,并更改为“poon”)并停止。我怎样才能让它继续下去,直到达到目标词 代码如下: #include <iostream> #include <queue> #include <stack> #include <string> using namespace std; struct Nod
while
循环中,它到达字典中的第一个单词(单词“toon”
,并更改为“poon”
)并停止。我怎样才能让它继续下去,直到达到目标词
代码如下:
#include <iostream>
#include <queue>
#include <stack>
#include <string>
using namespace std;
struct Node
{
string data;
Node* next;
};
void insert(string ele, Node*& head)
{
Node* newnode = new Node;
newnode->data = ele;
newnode->next = head;
head = newnode;
}
void del(string key, Node*& head)
{
Node* temp = head;
Node* prev = NULL;
if (temp != NULL && temp->data == key)
{
head = temp->next;
delete temp;
return;
}
else
{
while (temp != NULL && temp->data != key)
{
prev = temp;
temp = temp->next;
}
if (temp == NULL)
return;
prev->next = temp->next;
delete temp;
}
}
bool find(string key,Node *&head)
{
Node* p = head;
while (p != NULL)
{
if (p->data == key)
{
return true;
}
else
{
p = p->next;
}
}
if (p == NULL)
return false;
}
void print(Node*& head)
{
Node* p = head;
while (p != NULL)
{
cout << p->data;
p = p->next;
}
}
void WordLadder(string start, string target, Node*& head)
{
if (start == target)
cout << "They are the same";
if (find(target, head) != true)
cout << "Target Not found in dicionary";
//start word size
int wordlength = start.size();
//counter
int level = 0;
queue<string> q;
//push word in queue
q.push(start);
int len = 0;
while (!q.empty())
{
int wordlength = start.size();
int sizeofq = q.size();
string word = q.front();
q.pop();
for (int i = 0; i < wordlength ; i++)
{
for (char c = 'a'; c <= 'z'; c++)
{
word[i] = c;
if (word == target)
{
q.pop();
}
if (find(word, head) == true)
{
del(word, head);
q.push(word);
break;
}
}
}
}
cout << len;
}
int main()
{
Node* head = NULL;
insert("poon", head);
insert("plee", head);
insert("same", head);
insert("poie", head);
insert("plie", head);
insert("poin", head);
insert("plea", head);
string start = "toon";
string target = "plea";
WordLadder(start, target, head);
return 0;
}
#包括
#包括
#包括
#包括
使用名称空间std;
结构体类型
{
字符串数据;
节点*下一步;
};
无效插入(字符串元素、节点*&头)
{
Node*newnode=新节点;
newnode->data=ele;
新建节点->下一步=头部;
头=新节点;
}
void del(字符串键、节点*&头)
{
节点*温度=头部;
Node*prev=NULL;
if(temp!=NULL&&temp->data==key)
{
头=温度->下一步;
删除临时文件;
返回;
}
其他的
{
while(temp!=NULL&&temp->data!=key)
{
prev=温度;
温度=温度->下一步;
}
if(temp==NULL)
返回;
上一个->下一个=临时->下一个;
删除临时文件;
}
}
布尔查找(字符串键、节点*&头)
{
节点*p=头部;
while(p!=NULL)
{
如果(p->data==键)
{
返回true;
}
其他的
{
p=p->next;
}
}
if(p==NULL)
返回false;
}
无效打印(节点*&头)
{
节点*p=头部;
while(p!=NULL)
{
cout数据;
p=p->next;
}
}
无效字梯(字符串开始、字符串目标、节点*&头)
{
如果(开始==目标)
cout算法
看起来您的思路是正确的,尝试实现类似BFS的东西,所以我不打算详细解释“字梯”的算法。
但一个高层次的概述是:
将起始字推送到队列中
运行循环,直到队列为空
遍历与当前单词仅相差一个字符的所有单词,然后
将单词推入队列(对于BFS)
重复,直到我们找到目标单词或通读所有单词
您所犯的错误以及我如何修复这些错误:
在“wordlength”循环之前,您需要一个循环来遍历队列上的所有元素。虽然While
循环似乎正在这样做,但事实并非如此。我想您已经意识到这一点,因为您创建了sizeofq
变量,但从未使用过它。该循环如下所示:
for(int j = 0; j < sizeofq; j++) {
文体建议
<>你似乎是一个新的C++程序员,所以我想我会把我的想法留给这里的代码。
让函数返回结果,而不是打印结果,这被认为是一种很好的做法。它使您的代码更加灵活
你实现了自己的容器来完成这项工作,这有点像是重新发明轮子。C++ STL几乎总是包含一些可以让你的生活变得更容易的东西,所以在你开始工作之前就要搜索它。
如果你写的是一个更大的项目,不要使用<代码> >命名空间< /C> >,但是对于一个像这样的小玩具,它是好的。
< P>我已经在我的一个答案中说过,在C++中滚动你自己的容器常常会导致混淆和难以阅读的代码,这在解决问题时毫无帮助。
<>在现代C++(即C++ 11之后,现在理想地你应该使用C++ 17,甚至开始与C++ 20进行严格的交互),你几乎不需要像<代码>运算符new <代码>,<代码> null < /C>和指针(它们仍然是一个临时的解决方案,因为缺少<代码> STD::可选的< /C> >)
顺便说一句,我不认为需要使用队列来解决您的问题;一个“当前项”变量就足够了;然后,您可以通过搜索与当前元素的汉明距离为1的字符串列表来查找下一个元素。由于循环的可能性,它在一般情况下不起作用,但如果您只处理有限的单词列表,例如您的单词列表,而实际上只有一个可能的lad,那么它就足够了德
这就是我如何在C++20中快速建模您的问题:
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <ranges>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
using namespace std::literals;
// Simple implementation of Hamming's distance (see https://en.wikipedia.org/wiki/Hamming_distance)
std::size_t hamming_distance(const std::string_view s1, const std::string_view s2) {
std::size_t dist {};
if (s1.size() != s2.size()) {
throw std::runtime_error { "strings have different lengths, which is unsupported" };
}
auto it1 { s1.begin() };
auto it2 { s2.begin() };
const auto end1 { s1.end() };
while (it1 != end1) {
dist += *it1++ != *it2++;
}
return dist;
}
bool word_ladder(std::string_view start, const std::string_view target, std::vector<std::string> words) {
if (start == target) {
std::cout << "noop: start and target are the same\n";
return true;
}
// C++20's ranges - use std::find(std::begin(words), std::end(words), target) in older revisions
if (std::ranges::find(words, target) == std::end(words)) {
std::cerr << "error: target Not found in dictionary\n";
return false;
}
std::size_t len { 1U };
// Current word in the ladder - must be string because we are deleting them from the vector,
// so we must copy them
std::string word { start };
std::cout << word;
while (word != target) {
std::cout << "->";
// find an element in the dictionary has hamming(el, word) == 1 (i.e. 'cord' and 'core').
// this won't work if there's more than one match, because it will cause a loop.
// This is also based on C++20's ranges, and it can be replaced with std::find_if
const auto next_it { std::ranges::find_if(words, [word] (const auto el) { return hamming_distance(el, word) == 1; }) };
// no match, it means the chain can't be completed
if (next_it == std::end(words)) {
std::cout << "X (no result)\n";
return false;
}
// print the next element
std::cout << *next_it;
// set the next word as the newly found item
word = *next_it;
// remove it from the vector
// while this is O(n), it's empirically as fast as using a more "optimized" container
// due to how hecking fast vectors and memcpy are on modern CPUs
words.erase(next_it);
++len; // chain length counter
}
std::cout << "\nChain was " << len << " elements long\n";
return true;
}
int main() {
std::vector<std::string> words {
"poon",
"plee",
"same",
"poie",
"plie",
"poin",
"plea",
};
const auto start { "toon"sv };
const auto target { "plea"sv };
const bool success { word_ladder(start, target, std::move(words)) };
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
我使用了std::vector
而不是一个更“最优”的容器,因为它通常是最好的全方位选择,即使是在非常有限的系统上,因为现代CPU的速度有多快。链表尤其糟糕,应该(几乎)如此由于指针间接性带来的巨大开销,总是避免使用,这抵消了您可能从中获得的任何理论收益
通常,您应该使用向量和hashmap(即std::unordered_map)默认情况下,只在你真正需要的时候考虑其他容器。看起来你想用一种与BFS非常相似的算法。你可以尝试搜索它是如何建立的。我会尝试修复你的代码。你的代码看起来像C和C++之间的混合。你肯定应该重新实现一个链表。(STL中已有std::list
,用于std::string
和std::queue
),b.为什么你要使用诸如NULL
、操作符new
和裸指针之类的东西,而不是智能指针和移动语义和c.为什么你要首先使用链表?链表在现代机器上效率极低,与vector
和deque。此外,我会远离指针引用(即T*&)-事情可能会变得非常混乱。如果有任何方法比链表更好,请告诉我-如果您确实需要链表,只需使用std::vector
或std::list
(提示:您不需要)。如果没有很好的理由,重新发明轮子通常会导致代码质量下降,更难理解。在这里,我建议使用一些具有良好“查找”功能的数据结构(尽管您可以只对std::vector
进行排序)。我会使用一个std::set
。仔细阅读每一个的推荐用法,并为每一个选择最佳用法
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <ranges>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
using namespace std::literals;
// Simple implementation of Hamming's distance (see https://en.wikipedia.org/wiki/Hamming_distance)
std::size_t hamming_distance(const std::string_view s1, const std::string_view s2) {
std::size_t dist {};
if (s1.size() != s2.size()) {
throw std::runtime_error { "strings have different lengths, which is unsupported" };
}
auto it1 { s1.begin() };
auto it2 { s2.begin() };
const auto end1 { s1.end() };
while (it1 != end1) {
dist += *it1++ != *it2++;
}
return dist;
}
bool word_ladder(std::string_view start, const std::string_view target, std::vector<std::string> words) {
if (start == target) {
std::cout << "noop: start and target are the same\n";
return true;
}
// C++20's ranges - use std::find(std::begin(words), std::end(words), target) in older revisions
if (std::ranges::find(words, target) == std::end(words)) {
std::cerr << "error: target Not found in dictionary\n";
return false;
}
std::size_t len { 1U };
// Current word in the ladder - must be string because we are deleting them from the vector,
// so we must copy them
std::string word { start };
std::cout << word;
while (word != target) {
std::cout << "->";
// find an element in the dictionary has hamming(el, word) == 1 (i.e. 'cord' and 'core').
// this won't work if there's more than one match, because it will cause a loop.
// This is also based on C++20's ranges, and it can be replaced with std::find_if
const auto next_it { std::ranges::find_if(words, [word] (const auto el) { return hamming_distance(el, word) == 1; }) };
// no match, it means the chain can't be completed
if (next_it == std::end(words)) {
std::cout << "X (no result)\n";
return false;
}
// print the next element
std::cout << *next_it;
// set the next word as the newly found item
word = *next_it;
// remove it from the vector
// while this is O(n), it's empirically as fast as using a more "optimized" container
// due to how hecking fast vectors and memcpy are on modern CPUs
words.erase(next_it);
++len; // chain length counter
}
std::cout << "\nChain was " << len << " elements long\n";
return true;
}
int main() {
std::vector<std::string> words {
"poon",
"plee",
"same",
"poie",
"plie",
"poin",
"plea",
};
const auto start { "toon"sv };
const auto target { "plea"sv };
const bool success { word_ladder(start, target, std::move(words)) };
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
toon->poon->poin->poie->plie->plee->plea
Chain was 7 elements long