C++ 编写按字典顺序添加新元素的链接函数的更短/更有效的方法

C++ 编写按字典顺序添加新元素的链接函数的更短/更有效的方法,c++,c++11,linked-list,doubly-linked-list,C++,C++11,Linked List,Doubly Linked List,我试图练习编程原理和实践文本,花了一段时间进行调试,直到最终为函数编写了一个工作代码。演习是这样开始的: 我为链接创建了模板类: template<typename T> struct Link { T val; Link* prev; Link* succ; Link(const T& value, Link* p = nullptr, Link* s = nullptr) :val{value},prev {p}, suc

我试图练习编程原理和实践文本,花了一段时间进行调试,直到最终为函数编写了一个工作代码。演习是这样开始的: 我为链接创建了模板类:

template<typename T>
struct Link
{
    T val;
    Link* prev;
    Link* succ;

    Link(const T& value, Link* p = nullptr, Link* s = nullptr)
        :val{value},prev {p}, succ{ s } {}

    Link* add_ordered_(Link*);
};
我使用print_link函数打印出元素,以便于调试:

template<typename T>
void print_link(Link<T>* x)
{
    while (x)
    {
        cout << x->val << endl;
        x = x->prev;
    }
}
我编写的
add\u ordered\u
函数似乎太长、难看且效率低下。如果有人向我展示一种更有效的书写方法,我会很高兴的。

拆分您的方法:

std::pair<Link*, Link*> find_neighbor(const Link& link) {
    // assert(prev == nullptr);
    Link* left = nullptr; // == prev
    Link* right = this;

    while (right && right->val < link.val) {
        left = right;
        right = right->succ;
    }
    return {left, right};
}

void insert_between(Link* left, Link* right)
{
    prev = left;
    succ = right;
    if (left) {
        left->succ = this;   
    }
    if (right) {
        right->prev = this;   
    }
}

Link* add_ordered_(Link* link)
{
    // assert(prev == nullptr); // Assume we call it only with first element
    if (link == nullptr) {
        return this;   
    }
    auto p = find_neighbor(*link);
    link->insert_between(p.first, p.second);
    if (prev) {
        return prev; // == link
    }
    return this;
}
std::配对查找邻居(常量链接和链接){
//断言(prev==nullptr);
Link*left=nullptr;//==prev
链接*右=此;
while(right&&right->val成功;
}
返回{左,右};
}
在(链接*左,链接*右)之间插入空格
{
prev=左;
成功=正确;
如果(左){
左->成功=此;
}
如果(右){
右->上一个=这个;
}
}
链接*添加\订购\链接*链接
{
//assert(prev==nullptr);//假设我们只使用第一个元素调用它
if(link==nullptr){
归还这个;
}
自动p=查找邻居(*链接);
链接->插入(第一页,第二页);
如果(上一个){
返回上一个;//==链接
}
归还这个;
}
拆分您的方法:

std::pair<Link*, Link*> find_neighbor(const Link& link) {
    // assert(prev == nullptr);
    Link* left = nullptr; // == prev
    Link* right = this;

    while (right && right->val < link.val) {
        left = right;
        right = right->succ;
    }
    return {left, right};
}

void insert_between(Link* left, Link* right)
{
    prev = left;
    succ = right;
    if (left) {
        left->succ = this;   
    }
    if (right) {
        right->prev = this;   
    }
}

Link* add_ordered_(Link* link)
{
    // assert(prev == nullptr); // Assume we call it only with first element
    if (link == nullptr) {
        return this;   
    }
    auto p = find_neighbor(*link);
    link->insert_between(p.first, p.second);
    if (prev) {
        return prev; // == link
    }
    return this;
}
std::配对查找邻居(常量链接和链接){
//断言(prev==nullptr);
Link*left=nullptr;//==prev
链接*右=此;
while(right&&right->val成功;
}
返回{左,右};
}
在(链接*左,链接*右)之间插入空格
{
prev=左;
成功=正确;
如果(左){
左->成功=此;
}
如果(右){
右->上一个=这个;
}
}
链接*添加\订购\链接*链接
{
//assert(prev==nullptr);//假设我们只使用第一个元素调用它
if(link==nullptr){
归还这个;
}
自动p=查找邻居(*链接);
链接->插入(第一页,第二页);
如果(上一个){
返回上一个;//==链接
}
归还这个;
}

把事情分解成简单的小部分通常是个好主意

让我们向类中添加另外两个函数,
add\u在
之后和
add\u在
之前

template<typename T>
Link<T>* Link<T>::add_after(Link<T>*n)
{
    if (succ) {
        n->succ = succ;
    }

    succ = n;
    n->prev = this;
}

template<typename T>
Link<T>* Link<T>::add_before(Link<T>*n)
{
    if (prev) {
        n->prev = prev;
    }

    prev = n;
    n->succ = this;
}

把事情分解成简单的小部分通常是个好主意

让我们向类中添加另外两个函数,
add\u在
之后和
add\u在
之前

template<typename T>
Link<T>* Link<T>::add_after(Link<T>*n)
{
    if (succ) {
        n->succ = succ;
    }

    succ = n;
    n->prev = this;
}

template<typename T>
Link<T>* Link<T>::add_before(Link<T>*n)
{
    if (prev) {
        n->prev = prev;
    }

    prev = n;
    n->succ = this;
}

if(this==nullptr)
。无法发生(UB情况除外)。将方法分为两部分:查找插入位置。在位置插入。
if(this==nullptr)
。无法发生(UB情况除外)。将方法分为两部分:查找插入位置。插入位置。谢谢。真的很有帮助,谢谢。真的很有帮助。
template<typename T>
Link<T>* Link<T>::add_after(Link<T>*n)
{
    if (succ) {
        n->succ = succ;
    }

    succ = n;
    n->prev = this;
}

template<typename T>
Link<T>* Link<T>::add_before(Link<T>*n)
{
    if (prev) {
        n->prev = prev;
    }

    prev = n;
    n->succ = this;
}
template<typename T >
Link<T>* Link<T>::add_ordered_(Link<T>*n)
{
    Link* insert = this;
    if (n->val > insert->val) {
        insert->add_before(n);
        return n;
    }

    while (n->val < insert->val && insert->succ)
        insert = insert->succ;

    if (n->val > insert->val)
        insert->add_before(n);
    else
        insert->add_after(n);

    return this;
}