Skip to content

Alien dictionary (additional task) #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions additional_tasks/alien_dictionary/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Alien dictionary

Given a sorted dictionary (array of words) of an alien language, find the order of characters in the language.
For example, given the following dictionary:
### {"hl", "ld", "wd", "dd"}

The order of characters in the alien language is:
### "hlwd"

## P.S. The order of the characters must be unambiguously defined with the words in the dictionary.
If not, the program will determine the character order, which can be determined by the word order in the dictionary, but this character order may not be the only possible one.
7 changes: 7 additions & 0 deletions additional_tasks/alien_dictionary/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "utils.hpp"

int main() {
std::vector<std::string> dictionary = {"baa", "abcd", "abca", "cab", "cad"};
FindAlphabeticOrder(dictionary);
return 0;
}
61 changes: 61 additions & 0 deletions additional_tasks/alien_dictionary/src/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include <gtest/gtest.h>

#include <sstream>
#include <string>
#include <vector>

#include "utils.hpp"

// Helper function to capture the output of FindAlphabeticOrder
std::string CaptureOutput(const std::vector<std::string>& dictionary) {
std::ostringstream output;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'output' of type 'std::ostringstream' (aka 'basic_ostringstream') can be declared 'const' [misc-const-correctness]

Suggested change
std::ostringstream output;
std::ostringstream const output;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'output' of type 'std::ostringstream' (aka 'basic_ostringstream') can be declared 'const' [misc-const-correctness]

Suggested change
std::ostringstream output;
std::ostringstream const output;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'output' of type 'std::ostringstream' (aka 'basic_ostringstream') can be declared 'const' [misc-const-correctness]

Suggested change
std::ostringstream output;
std::ostringstream const output;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'output' of type 'std::ostringstream' (aka 'basic_ostringstream') can be declared 'const' [misc-const-correctness]

Suggested change
std::ostringstream output;
std::ostringstream const output;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'output' of type 'std::ostringstream' (aka 'basic_ostringstream') can be declared 'const' [misc-const-correctness]

Suggested change
std::ostringstream output;
std::ostringstream const output;

std::streambuf* oldCoutBuffer =
std::cout.rdbuf(output.rdbuf()); // Redirect cout to output stream

FindAlphabeticOrder(dictionary); // Call the function

std::cout.rdbuf(oldCoutBuffer); // Restore cout
return output.str();
}

TEST(AlienDictionaryTests, SimpleTest) {
std::vector<std::string> dictionary = {"hl", "ld", "wd", "dd"};
std::string output = CaptureOutput(dictionary);
ASSERT_EQ(output, "hlwd\n"); // Expected order
}

TEST(AlienDictionaryTests, BasicOrderTest) {
std::vector<std::string> dictionary = {"baa", "abcd", "abca", "cab", "cad"};
std::string output = CaptureOutput(dictionary);
ASSERT_EQ(output, "bdac\n"); // Expected order
}

TEST(AlienDictionaryTests, NoOrderTest) {
std::vector<std::string> dictionary = {"abc", "bca", "bac", "cab"};
std::string output = CaptureOutput(dictionary);
ASSERT_EQ(output,
"The graph contains a cycle. Topological sorting is not "
"determined.\n"); // Cycle detected
}

TEST(AlienDictionaryTests, SingleWordTest) {
std::vector<std::string> dictionary = {"a"};
std::string output = CaptureOutput(dictionary);
ASSERT_EQ(output, "a\n"); // Only one character
}

TEST(AlienDictionaryTests, EmptyDictionaryTest) {
std::vector<std::string> dictionary = {};
std::string output = CaptureOutput(dictionary);
ASSERT_EQ(output, ""); // No output for empty dictionary
}

TEST(AlienDictionaryTests, ComplexOrderTest) {
// Updated dictionary to test a different order
std::vector<std::string> dictionary = {"aaa", "abb", "bat", "bar",
"cab", "cat", "tar", "rat"};

// Updated expected output based on the new dictionary
std::string output = CaptureOutput(dictionary);
ASSERT_EQ(output, "abctr\n"); // Check for possible valid orders
}
88 changes: 88 additions & 0 deletions additional_tasks/alien_dictionary/src/utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include "utils.hpp"

void ForceAddDirEdge(Graph<char>& graph, char u, char v) {
// Add vertices if they do not exist
if (graph.Size() == 0 || graph.Find(u) == graph.Size()) {
graph.AddVertex(u);
}
if (graph.Find(v) == graph.Size()) {
graph.AddVertex(v);
}
// Add directed edge from u to v
graph.AddDirEdge(graph.Find(u), graph.Find(v));
}

bool TopologicalSortStep(Graph<char>& graph, size_t v, std::set<char>& visited,
std::set<char>& recursion, std::stack<char>& stack) {
// Mark the current node as visited and add it to the recursion stack
visited.insert(graph[v]->data);
recursion.insert(graph[v]->data);

// Recur for all the vertices adjacent to this vertex
for (const auto& neighbor : graph[v]->adjacent) {
if (recursion.find(neighbor->data) != recursion.end()) {
// If the neighbor is in the recursion stack, we found a cycle
return true;
}
if (visited.find(neighbor->data) == visited.end()) {
if (TopologicalSortStep(graph, graph.Find(neighbor->data), visited,
recursion, stack)) {
return true; // Cycle detected in the recursive call
}
}
}

// Remove the vertex from recursion and add it to the result
recursion.erase(graph[v]->data);
stack.push(graph[v]->data);
return false; // No cycle detected
}

void FindAlphabeticOrder(const std::vector<std::string>& words) {
if (words.empty()) return; // No words to sort

// Only one word, thus it contains the only character
if (words.size() == 1) {
std::cout << words[0] << std::endl;
return;
}

Graph<char> graph;

// Build the graph by iterating through adjacent words
for (size_t i = 0; i < words.size() - 1; ++i) {
std::string curr_word = words[i];
std::string next_word = words[i + 1];
size_t minLength = std::min(curr_word.length(), next_word.length());

for (size_t j = 0; j < minLength; ++j) {
if (curr_word[j] != next_word[j]) {
ForceAddDirEdge(graph, curr_word[j], next_word[j]);
break; // Only the first different character matters
}
}
}

// Perform topological sorting and check for cycles
std::set<char> visited;
std::set<char> recursion; // To keep track of the recursion
std::stack<char> result;

for (size_t i = 0; i < graph.Size(); ++i) {
if (visited.find(graph[i]->data) == visited.end()) {
if (TopologicalSortStep(graph, i, visited, recursion, result)) {
std::cout << "The graph contains a cycle. Topological sorting is not "
"determined."
<< std::endl;
return; // Cycle detected
}
}
}

// Print the characters in reverse order
while (!result.empty()) {
std::cout << result.top();
result.pop();
}
std::cout << std::endl;
}
16 changes: 16 additions & 0 deletions additional_tasks/alien_dictionary/src/utils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <stack>

#include "graph.hpp"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 'graph.hpp' file not found [clang-diagnostic-error]

#include "graph.hpp"
         ^


// Adds a directed edge between characters u and v
// Processes if this is the first occurrence for any of the characters
void ForceAddDirEdge(Graph<char>& graph, char u, char v);

// DFS, performing topological sort and detecting cycles
bool TopologicalSortStep(Graph<char>& graph, size_t v, std::set<char>& visited,
std::set<char>& recursion, std::stack<char>& stack);

// Function to process the words and find the character order
void FindAlphabeticOrder(const std::vector<std::string>& dictionary);
3 changes: 0 additions & 3 deletions additional_tasks/template_task/README.md

This file was deleted.

1 change: 0 additions & 1 deletion additional_tasks/template_task/src/main.cpp

This file was deleted.

8 changes: 0 additions & 8 deletions additional_tasks/template_task/src/test.cpp

This file was deleted.

1 change: 0 additions & 1 deletion additional_tasks/template_task/src/utils.cpp

This file was deleted.

1 change: 0 additions & 1 deletion additional_tasks/template_task/src/utils.hpp

This file was deleted.

Loading
Loading