DEV Community

Srikanth Anantharam
Srikanth Anantharam

Posted on • Edited on • Originally published at blog.srikanth.one

Swapping the position of the two words in a string represented by a singly linked list

Recently I've been giving interviews as my last contract got completed. In one of the interviews, I was asked to write a data structure for a string using a singly linked list. The constraint was that the string would have exactly two words separated by a space. The task was to swap the position of the two words in an efficient way.

I started thinking and at the high level, it looked like a simple task where I had to just restructure the list by reassigning some of the pointers.

After some deliberation, I started writing the code to accomplish the task. Working with linked lists is something that we programmers rarely do in the real world. So, It took me a while to complete even half of the task (i.e., to move the second word to the beginning) and due to time constraints I couldn't complete the task during the interview. But I endured post the call and completed the task.

So, the following is the code for the algorithm that I came up with taking into account the edge cases that I could think of. I have tried to name the variables to be intuitive and have given some comments to improve the understanding.

#include <iostream>
#include <stdexcept>
#include <cstring>

using namespace std;

/**
 * @brief This class represents a string as a singly linked list.
 */
class StringAsSinglyLinkedList {
private:
    /**
     * @brief This nested class represents a node in the linked list.
     */
    class Node {
        char data; /** The character that represents the data stored in the node. */
        Node * next; /** A pointer to the next node in the linked list. */
        /**
         * @brief A constructor that creates a new node with the given data and next pointer.
         * @param data The character that represents the data stored in the node.
         * @param next A pointer to the next node in the linked list.
         */
        Node(const char data, Node * next) : data(data), next(next) {}
        friend class StringAsSinglyLinkedList;
    };
    Node * head; /**< A pointer to the first node in the linked list. */
    Node * tail; /**< A pointer to the last node in the linked list. */

public:
    /**
     * @brief A constructor that creates a new instance of the StringAsSinglyLinkedList class with the given C-style string.
     * @param s The C-style string to initialize the linked list with. The string must be contain exactly one space character.
     */
    StringAsSinglyLinkedList(const char * s) : head(nullptr), tail(nullptr) {
        Node * node = nullptr;
        for (int i = strlen(s) - 1; i >= 0; i--) {
            node = new Node(s[i], node);
            if (i == 0) {
                tail = node;
            }
        }
        head = node;
    }

    /**
     * @brief A method that restructures the linked list by effectively swapping the first word and the second word in the list.
     * It does this by finding the first space character in the list, breaking the list at that point,
     * and then appending the first part of the list to the end of the second part.
     */
    void restructure() {
        Node * current_node = head;
        Node * end_of_the_first_word = nullptr;
        // Loop to find the end of the first word and the space character in the string.
        while(current_node) {
            if (current_node->data == ' ') {
                break;
            }
            end_of_the_first_word = current_node;
            current_node = current_node->next;
        }
        if (current_node) { // Check to make sure the string contains a space character.
            if (current_node->next) { // Check to make sure the string contains more than one word.
                Node * node_containing_space = current_node; // Create a node to store the node containing the space character.
                Node * temporary_node = head; // Create a temporary node to store the head.
                head = node_containing_space->next; // Make the head point to the beginning of the second word.
                tail = end_of_the_first_word; // Make the tail point to the end of the first word.
                end_of_the_first_word->next = nullptr; // Break the list at the end of the first word.
                current_node = head;
                // Loop to find the end of the second word.
                while(current_node->next) {
                    current_node = current_node->next;
                }
                current_node->next = node_containing_space; // Append the space character to the end of the second word.
                node_containing_space->next = temporary_node; // Append the first word to the end of the second word.
            }
        }
    }

    /**
     * @brief A method that displays the characters in the linked list in their original order.
     */
    void display() {
        Node * node = head;
        while(node) {
            cout << node->data;
            node = node->next;
        }
        cout << endl;
    }

    /**
     * @brief A destructor that frees the memory allocated for the linked list.
     */
    ~StringAsSinglyLinkedList() {
        while(head) {
            Node * node = head->next;
            delete head;
            head = node;
        }
    }
};

/**
 * @brief The main function creates an instance of the StringAsSinglyLinkedList class with the string "Srikanth Anantharam".
 * It then displays the original string and the restructured string by calling the display method before and after calling the restructure method, respectively.
 * @return 0 if the program exits successfully.
 */
int main()
{
    auto sasll = StringAsSinglyLinkedList("Srikanth Anantharam");
    sasll.display();
    sasll.restructure();
    sasll.display();

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Thanks to the reddit user witcher_rat for pointing out. There is an idiomatic way to do this using the STL. The following is the code for the same.

#include <forward_list>
#include <iostream>
#include <string_view>

/**
 * @brief A class that represents a string as a singly linked list.
 */
struct String final {
    /**
     * @brief Constructs a String object from a string view.
     * @param sv The string view to construct the String object from.
     */
    String(std::string_view sv) : chars(sv.begin(), sv.end()) {}

    /**
     * @brief Restructures the string by swapping the first word and the second word.
     */
    void restructure()
    {
        auto it = chars.begin();
        if (it == chars.end()) return; // return if the string is empty

        for (auto prev = it++; it != chars.end(); ++it, ++prev) {
            if (*it == ' ') { // if we find a space
                // use splice_after to move the space to the beginning
                // the first argument to splice_after is the position to move the element to
                // the second argument is the list to move the element from
                // the third argument is the position of the element to move
                chars.splice_after(chars.before_begin(), chars, prev);

                // and then move the remaining chars to the beginning
                // the first argument to splice_after is the position to move the elements to
                // the second argument is the list to move the elements from
                // the third and fourth arguments are the range of elements to move
                chars.splice_after(chars.before_begin(), chars, prev, chars.end());
                return;
            }
        }
    }

    /**
     * @brief Outputs the string to an output stream.
     * @param os The output stream to output the string to.
     * @param s The String object to output.
     * @return The output stream.
     */
    friend std::ostream& operator<<(std::ostream& os, const String& s)
    {
        for (auto c : s.chars) os << c;
        return os;
    }

  private:
    std::forward_list<char> chars;
};

/**
 * @brief The main function that demonstrates the String class.
 * @return 0 on success.
 */
int main() {
    String name("Srikanth Anantharam");
    std::cout << name << std::endl;
    name.restructure();
    std::cout << name << std::endl;
}
Enter fullscreen mode Exit fullscreen mode

Link to the code

Try online in a new Codespace

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay