Cod sursa(job #2631043)

Utilizator horiacoolNedelcu Horia Alexandru horiacool Data 28 iunie 2020 17:01:49
Problema Sortare prin comparare Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 16.2 kb
// Copyright 2019 Nedelcu Horia ([email protected])

/**
*    SkipList Implementation:
*   
*    I implemented the data structure so that it can store items
* of the same value without wasting memory (each node keeps the number
* of times the key appears, count). Also I wanted the data structure to
* supports random access by index and key, insertion and deletion in
* logarithmic time with order maintained. For this I have kept 2 LOGN SIZE
* vectors representing the path to find a node and the index of each node
* in the path (path, index_path, details in implementation).
*    Search to find by key / index:
*    The search starts at the highest level and attempts to move to the
* right (next) as long as the key is lower or the number of nodes that are
* skipped doesn't exceed the index.
*/

#ifndef SKIP_LIST_H_
#define SKIP_LIST_H_

#include <ctime>
#include <random>
#include <iostream>
#include <exception>

#define N_MAX 200000
#define H_MAX 20
#define JUMP_TO_NULL -1

template <class T> class DefaulComparator;
template <class T> class Node;
template <class T, class Comparator = DefaulComparator<T> > class SkipList;

template <class T>
class DefaulComparator {
 public:
    bool operator()(T const &lhs, T const &rhs) {
        return lhs > rhs;
    }
};

template <class T>
class Node {
 public:
    T data_;
    int count_;
    Node **next_;
    int *jump_;

    Node(T, int, int count_ = 1);
    Node(Node<T>&);
    ~Node();
    Node& operator=(Node<T>&);
};

template <class T, class Comparator>
class SkipList {
    int max_capacity_;
    int max_height_;
    int num_elem_;
    int num_nodes_;
    int *index_path_;
    Node<T> **path_, *head_;
    Comparator comp_;
    std::minstd_rand new_rand_;

 public:
    SkipList();
    SkipList(const SkipList<T, Comparator>&);
    ~SkipList();
    SkipList<T, Comparator>& operator=(const SkipList<T, Comparator>&);

    class iterator {
        Node<T>* itr;

     public:
        iterator();
        explicit iterator(Node<T>*);
        iterator(const iterator&);

        iterator& operator=(const iterator&);
        bool operator==(const iterator&);
        bool operator!=(const iterator&);
        iterator& operator++();
        const T& operator*();
    };

    iterator begin();
    iterator end();
    iterator findKey(const T&);

    int size();
    int length();
    int capacity();
    bool isEmpty();

    int countKey(const T&);
    bool searchKey(const T&);
    void insertKey(const T&, int count_ = 1);
    void eraseKey(const T&, int count_ = 1);

    const T& topKey();
    const T& operator[](int index);

 private:
    int getNewHeight();
};

/*
 * Implementation:
 */

template <class T>
Node<T> :: Node(T data, int height, int count): data_(data),
    count_(count), next_(nullptr), jump_(nullptr) {
    try {
        next_ = new Node<T>*[height]();
        jump_ = new int[height]();

        for (int i = 0; i < height; ++i) {
            jump_[i] = JUMP_TO_NULL;
        }
    } catch (std::exception& e) {
        std::cerr << "Standard exception: " << e.what() << '\n';
    }
}

template <class T>
Node<T> :: ~Node() {
    delete[] next_;
    delete[] jump_;
}

/*
 * These are shallow copy assignments and constructor (Rule of three).
 * Each node doesn't preserve its height, because it doesn't need and
 * it is a waste of memory.
 */
template <class T>
Node<T> :: Node(Node<T>& other) = default;

template <class T>
Node<T>& Node<T> :: operator=(Node<T>& other) = default;

template <class T, class Comparator>
SkipList<T, Comparator> :: iterator ::
iterator(): itr(nullptr) {}

template <class T, class Comparator>
SkipList<T, Comparator> :: iterator ::
iterator(Node<T>* other_itr): itr(other_itr) {}

template <class T, class Comparator>
SkipList<T, Comparator> :: iterator ::
iterator(const iterator& other): itr(other.itr) {}

template <class T, class Comparator>
typename SkipList<T, Comparator> :: iterator&
SkipList<T, Comparator> :: iterator ::
operator=(const iterator& other) {
    itr = other.itr;
    return *this;
}

template <class T, class Comparator>
bool
SkipList<T, Comparator> :: iterator ::
operator== (const iterator& other) {
    return itr == other.itr;
}

template <class T, class Comparator>
bool
SkipList<T, Comparator> :: iterator ::
operator!= (const iterator& other) {
    return itr != other.itr;
}

template <class T, class Comparator>
typename SkipList<T, Comparator> :: iterator&
SkipList<T, Comparator> :: iterator ::
operator++() {
    itr = itr->next_[0];
    return *this;
}

template <class T, class Comparator>
const T&
SkipList<T, Comparator> :: iterator ::
operator*() {
    return itr->data_;
}

template <class T, class Comparator>
SkipList<T, Comparator> :: SkipList(): max_capacity_(N_MAX), max_height_(H_MAX),
    num_elem_(0), num_nodes_(0), index_path_(nullptr), path_(nullptr),
    head_(nullptr), comp_(), new_rand_() {
    unsigned int seed = static_cast<unsigned int>(time(nullptr));
    T tmp = T();

    try {
        head_ = new Node<T>(tmp, max_height_);
        path_ = new Node<T>*[max_height_];
        index_path_ = new int[max_height_]();
    } catch (std::exception& e) {
        std::cerr << "Standard exception: " << e.what() << '\n';
    }

    new_rand_.seed(seed);
}

template <class T, class Comparator>
SkipList<T, Comparator> :: SkipList(const SkipList<T, Comparator>& other):
    max_capacity_(other.max_capacity_), max_height_(other.max_height_),
    num_elem_(other.num_elem_), num_nodes_(other.num_nodes_),
    index_path_(nullptr), path_(nullptr), head_(nullptr),
    comp_(), new_rand_() {
    unsigned int seed = static_cast<unsigned int>(time(nullptr));
    T tmp = T();

    try {
        head_ = new Node<T>(tmp, max_height_);
        path_ = new Node<T>*[max_height_];
        index_path_ = new int[max_height_]();
    } catch (std::exception& e) {
        std::cerr << "Standard exception: " << e.what() << '\n';
    }

    SkipList<T, Comparator> :: iterator it;
    for (it = other.begin(); it != other.end(); ++it) {
        this->insertKey(*it);
    }

    new_rand_.seed(seed);
}

template <class T, class Comparator>
SkipList<T, Comparator> :: ~SkipList() {
    Node<T>* tmp;

    while (head_) {
        tmp = head_;
        head_ = head_->next_[0];
        delete tmp;
    }

    delete[] path_;
    delete[] index_path_;
}

template <class T, class Comparator>
SkipList<T, Comparator>&
SkipList<T, Comparator> :: operator=(const SkipList<T, Comparator>& other) {
    Node<T>* tmp_node;

    while (head_) {
        tmp_node = head_;
        head_ = head_->next_[0];
        delete tmp_node;
    }

    delete[] path_;
    delete[] index_path_;

    max_capacity_ = other.max_capacity_;
    max_height_ = other.max_height_;
    num_elem_ = other.num_elem_;
    num_nodes_ = other.num_nodes_;

    T tmp = T();

    try {
        head_ = new Node<T>(tmp, max_height_);
        path_ = new Node<T>*[max_height_];
        index_path_ = new int[max_height_]();
    } catch (std::exception& e) {
        std::cerr << "Standard exception: " << e.what() << '\n';
    }

    SkipList<T, Comparator> :: iterator it;
    for (it = other.begin(); it != other.end(); ++it) {
        this->insertKey(*it);
    }
}

template <class T, class Comparator>
typename SkipList<T, Comparator> :: iterator
SkipList<T, Comparator> :: begin() {
    return iterator(head_->next_[0]);
}

template <class T, class Comparator>
typename SkipList<T, Comparator> :: iterator
SkipList<T, Comparator> :: end() {
    return iterator(nullptr);
}

/*
 * Search for key in skip list and return an iterator to its
 * position or end iterator otherwise.
 * O(logn)
 */
template <class T, class Comparator>
typename SkipList<T, Comparator> :: iterator
SkipList<T, Comparator> :: findKey(const T& key) {
    Node<T> *it = head_;

    for (int i = max_height_ - 1; i > -1; --i) {
        while (it->next_[i] && comp_(key, it->next_[i]->data_)) {
            it = it->next_[i];
        }
    }

    if (!it->next_[0] || key != it->next_[0]->data_) {
        return iterator(nullptr);
    } else {
        return iterator(it->next_[0]);
    }
}

template <class T, class Comparator>
int
SkipList<T, Comparator> :: size() {
    return num_elem_;
}

template <class T, class Comparator>
int
SkipList<T, Comparator> :: length() {
    return num_nodes_;
}

template <class T, class Comparator>
int
SkipList<T, Comparator> :: capacity() {
    return max_capacity_;
}

template <class T, class Comparator>
bool
SkipList<T, Comparator> :: isEmpty() {
    return num_nodes_ == 0;
}

/*
 * Search for key in skip list and returns how many
 * times the key is on the skip list.
 * O(logn)
 */
template <class T, class Comparator>
int
SkipList<T, Comparator> :: countKey(const T& key) {
    Node<T> *it = head_;

    for (int i = max_height_ - 1; i > -1; --i) {
        while (it->next_[i] && comp_(key, it->next_[i]->data_)) {
            it = it->next_[i];
        }
    }

    if (!it->next_[0] || key != it->next_[0]->data_) {
        return 0;
    } else {
        return it->next_[0]->count_;
    }
}

template <class T, class Comparator>
bool
SkipList<T, Comparator> :: searchKey(const T& key) {
    return countKey(key);
}

/*
 * Insert count keys in the skip list (count = 1 default).
 * O(logn)
 */
template <class T, class Comparator>
void
SkipList<T, Comparator> :: insertKey(const T& key, int count) {
    try {
        if (count < 1) {
            throw 1;
        }
    } catch (...) {
        std::cerr << "Standard exception: insertKey negative number of keys\n";
        return;
    }

    num_elem_ += count;

    int height, curr_index, old_jump;
    Node<T> *tmp, *node, *it;

    if (!searchKey(key)) {
        ++num_nodes_;

        height = getNewHeight();
        curr_index = 0;

        node = new Node<T>(key, height, count);
        it = head_;

        for (int i = max_height_ - 1; i > -1; --i) {
            while (it->next_[i] && comp_(key, it->next_[i]->data_)) {
                curr_index += it->jump_[i] + 1;
                it = it->next_[i];
            }

            // For each level retain the last node and its position in skiplist
            // jump_ specify the node level how many nodes skip
            index_path_[i] = curr_index;
            path_[i] = it;
        }


        // Nodes at the same height point to the
        // new node levels and change their jump_
        tmp = path_[0]->next_[0];
        path_[0]->next_[0] = node;
        node->next_[0] = tmp;

        old_jump = path_[0]->jump_[0];
        path_[0]->jump_[0] = 0;
        node->jump_[0] = old_jump;  // 0 or JUMP_TO_NULL

        for (int i = 1; i < height; ++i) {
            tmp = path_[i]->next_[i];
            path_[i]->next_[i] = node;
            node->next_[i] = tmp;

            old_jump = path_[i]->jump_[i];
            // The current node jumps as many nodes as it reaches the node on a
            // lower level path + as many nodes as it reaches the node inserted
            path_[i]->jump_[i] = index_path_[i - 1] - index_path_[i]
                + path_[i - 1]->jump_[i - 1];
            // The inserted node jumps over remained nodes or jumps to NULL
            node->jump_[i] = (old_jump == JUMP_TO_NULL)? JUMP_TO_NULL:
                old_jump - path_[i]->jump_[i];
        }

        // The rest of the path with higher levels jump over an extra node
        for (int i = height; i < max_height_; ++i) {
            if (path_[i]->jump_[i] != JUMP_TO_NULL) {
                ++path_[i]->jump_[i];
            }
        }
    } else {
        it = head_;

        for (int i = max_height_ - 1; i > -1; --i) {
            while (it->next_[i] && comp_(key, it->next_[i]->data_)) {
                it = it->next_[i];
            }
        }

        it->next_[0]->count_ += count;
    }
}

/*
 * Erase count keys from the skip list (count = 1 default).
 * O(logn)
 */
template <class T, class Comparator>
void
SkipList<T, Comparator> :: eraseKey(const T& key, int count) {
    try {
        if (count < 1) {
            throw 1;
        }
    } catch (...) {
        std::cerr << "Standard exception: eraseKey negative number of keys\n";
        return;
    }

    int get_count = countKey(key);
    Node<T> *tmp, *it = head_;

    if (get_count < 1) {
        return;
    }

    for (int i = max_height_ - 1; i > -1; --i) {
        while (it->next_[i] && comp(key, it->next_[i]->data_)) {
            it = it->next_[i];
        }

        path_[i] = it;
    }

    if (it->next_[0]->count_ > count) {
        num_elem_ -= count;
    } else {
        num_elem_ -= it->next_[0]->count_;
    }

    it->next_[0]->count_ -= count;
    if (it->next_[0]->count_ < 1) {
        --num_nodes_;

        tmp = it->next_[0];

        for (int i = 0; i < max_height_; ++i) {
            if (path_[i]->next_[i] != tmp) {
            	// jump less with one node
                if (path_[i]->next_[i]) {
                	// no jump to NULL
                    --path_[i]->jump_[i];
                }
            } else {
                path_[i]->next_[i] = tmp->next_[i];

                // check if now jump to NULL
                if (path_[i]->next_[i]) {
                    path_[i]->jump_[i] += tmp->jump_[i];
                } else {
                    path_[i]->jump_[i] = JUMP_TO_NULL;
                }
            }
        }

        delete tmp;
    }
}

template <class T, class Comparator>
const T&
SkipList<T, Comparator> :: topKey() {
    try {
        if (num_nodes_ < 1) {
            throw 1;
        }
    } catch (...) {
        std::cerr << "Standard exception: empty list\n";
    }

    return head_->next_[0]->data_;
}

/*
 * Return date from position index in skip list.
 * O(logn)
 */
template <class T, class Comparator>
const T&
SkipList<T, Comparator> :: operator[](int index) {
    try {
        if (index < 0 || num_nodes_ <= index) {
            throw 1;
        }
    } catch (...) {
        std::cerr << "Standard exception: index outside the bounds\n";
    }

    ++index;
    Node<T> *it = head_;
    for (int i = max_height_ - 1; i > -1; --i) {
        while (it->next_[i] && index >= it->jump_[i] + 1) {
            index -= it->jump_[i] + 1;
            it = it->next_[i];
        }
    }

    return it->data_;
}

template <class T, class Comparator>
int
SkipList<T, Comparator> :: getNewHeight() {
    int height, random;

    for (height = 1, random = new_rand_(); random & 1 && height < max_height_;
        random = (random >>= 1)? random: new_rand_(), ++height) {
    }

    return height;
}

/*
 * I've left commented code and the worse method to show that
 * the data structure supports random access by index and key,
 * insertion, deletion in logarithmic time with order maintained.
 */
template <class T, class Container>
int sortAlgorithm(T* vect, int size, bool distinct) {
    // typename Container :: iterator it;
    Container sklist;
    int i, j, k, count;

    // O(nlogn)
    for (i = 0; i < size; ++i) {
        sklist.insertKey(vect[i]);
    }

    // sort and eliminate replicates
    if (distinct == true) {
        // O(nlogn)
        for (i = 0; i < sklist.length(); ++i) {
            vect[i] = sklist[i];
        }

        // O(n)
        // for (i = 0, it = sklist.begin(); it != sklist.end(); ++it) {
        //    vect[i++] = *it;
        // }

        return sklist.length();
    } else {  // just sort
        // O(k*nlogn)
        for (i = j = 0; i < sklist.length(); ++i) {
            count = sklist.countKey(sklist[i]);

            for (k = 0; k < count; ++k) {
                vect[j++] = sklist[i];
            }
        }

        // O(k*n)
        // for (j = 0, it = sklist.begin(); it != sklist.end(); ++it) {
        //     count = sklist.countKey(*it);

        //     for (k = 0; k < count; ++k) {
        //         vect[j++] = *it;
        //     }
        // }

        return sklist.size();
    }
}

/*
 * This sorting functions return also the size if it was changed
 * by calling them with the parameter distinct equal to true.
 */
template <class T, class Comparator>
int skipListSort(T* vect, int size, bool distinct = false) {
    return sortAlgorithm<T, SkipList<T, Comparator> >(vect, size, distinct);
}

template <class T>
int skipListSort(T* vect, int size, bool distinct = false) {
    return sortAlgorithm<T, SkipList<T> >(vect, size, distinct);
}

#endif  // SKIP_LIST_H_

int main() {
    int n, v[500003];

    std::cin >> n;
    for (int i = 0; i < n; ++i) {
        std::cin >> v[i];
    }

    skipListSort<int>(v, n);

    for (int i = 0; i < n; ++i) {
        std::cout << v[i] << ' ';
    }
}