Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 插入节点时对链表排序_C++_Algorithm_Sorting_Linked List - Fatal编程技术网

C++ 插入节点时对链表排序

C++ 插入节点时对链表排序,c++,algorithm,sorting,linked-list,C++,Algorithm,Sorting,Linked List,我正在尝试创建排序链表=在创建时对其排序。想法很简单,插入一个节点,然后检查previous是否较小,如果较小,则检查previous的previous,依此类推,直到找到它的位置。我已经创建了这段代码 struct Node{ Node *prev; Node *next; int value; }; struct List{ Node *head = nullptr; Node *tail = nullptr; }; 在这里,我创建了一个节点和列表

我正在尝试创建排序链表=在创建时对其排序。想法很简单,插入一个节点,然后检查previous是否较小,如果较小,则检查previous的previous,依此类推,直到找到它的位置。我已经创建了这段代码

struct Node{
    Node *prev;
    Node *next;
    int value;
};

struct List{
    Node *head = nullptr;
    Node *tail = nullptr;
};
在这里,我创建了一个节点和列表的“holder”=引用列表的第一项和最后一项

void insertNode(Node *&head,Node *&tail, int value ){
    Node *tmp = new Node;
    tmp -> prev = nullptr;
    tmp -> next = nullptr;
    tmp -> value = value;
    head = tmp;
    tail = tmp;
}
此函数检查列表是否为空,如果为空,则将节点插入头部和尾部(例如头部=尾部=列表中只有一个节点)

困扰我的是插入节点的函数

void insertIt(Node *&head , Node *&tail , int value){
    if( head == nullptr){
        insertNode(head,tail,value);
    }
    else{
        Node *tmp = new Node;
        tmp -> value = value;

        if( value < tail -> value){    
            while(value < tail -> prev -> value){                
                tail = tail -> prev;
                if( tail -> prev == nullptr){                    
                    tmp -> next = head;
                    tmp -> prev = nullptr;
                    head -> prev = tmp;
                    head = tmp;
                    return;
                }
            }
            tail -> prev -> next = tmp;
            tmp -> prev =  tail -> prev;
            tmp -> next = tail;
            tail -> prev = tmp;
        }else{    
            tmp -> next = nullptr;
            tmp ->prev = tail;
            tail -> next = tmp;
            tail = tmp;
        }
    }
}
工作,如果我打印列表,它是很好的排序。但是

insertIt(list.head , list.tail , -2);
insertIt(list.head , list.tail , -1);
insertIt(list.head , list.tail , 7);
insertIt(list.head , list.tail , 1);
insertIt(list.head , list.tail , 2);
insertIt(list.head , list.tail , 2);
第一个节点不是最小的节点,它会使程序崩溃。我以为是我在比较一个值和nullptr,所以我添加了一段代码,您可以在
insertIt()
函数中看到这段代码

if( tail -> prev == nullptr){
    tmp -> next = head;
    tmp -> prev = nullptr;
    head -> prev = tmp;
    head = tmp;
    return;
}
这将检查节点是否为头,并将头与新节点交换,使新节点成为新头


为什么它会导致代码崩溃?我没能找到一个合理的答案。另外,我如何改进我的“算法”使其更有效?

您想做两件事:在新节点所属的列表中查找位置,并在某个位置插入新节点。因此,编写两个函数,每个任务一个函数。然后可以在集成之前分别测试和调试它们。这将更加直截了当。进一步建议:在实现函数之前,为每个函数编写单元测试

/** Find node with largest value less than given 
    Assumes sorted list exist.  If empty, throws exception
*/
Node & FindLessThan( int value );

/** Inset new node after given with value */
InsertAfter( Node& n, int value );
如果列表为空,还可以使用插入第一个节点的函数

/** Insert first node with value
    @return true if list empty */
bool InsertFirstNode( int value );
关键是,您应该隐藏所有可以测试的函数中的指针旋转,这样您就可以编写一条可理解的主线,第一次工作:

if( ! InsertFirstNode( value ) )
   InsertAfter( FindLessThan( value ), value );

因为你使用C++,所以你的列表要有一个类和函数成员.< /p> 实现细节:您必须担心特殊情况:新值在head之前或尾部之后。所以我建议使用枚举来处理这些问题

/** Special cases for placing a new node */
enum class eFind
{
    list_empty,         // the list was empty
    before_first,       // the new node goes before the first node in list
    before_node,        // the new node goes before the specified node
    after_last,         // the new node goes after the last node in the list
}; 
/** Find node with smallest value greater than given

    @param[out] place eFind enumeration, one of list_empty,before_first,before_node,after_last
    @param[in] value being inserted

    @return n node before which value should be placed

    Assumes sorted list exist.
*/
Node * FindSmallestGreaterThan( eFind & place, int value )

事实证明,在插入之前比在插入之后更容易(代码更少)。您可以看到运行在或

上的代码,您需要做两件事:在新节点所属的列表中查找位置,并在某个位置插入新节点。因此,编写两个函数,每个任务一个函数。然后可以在集成之前分别测试和调试它们。这将更加直截了当。进一步建议:在实现函数之前,为每个函数编写单元测试

/** Find node with largest value less than given 
    Assumes sorted list exist.  If empty, throws exception
*/
Node & FindLessThan( int value );

/** Inset new node after given with value */
InsertAfter( Node& n, int value );
如果列表为空,还可以使用插入第一个节点的函数

/** Insert first node with value
    @return true if list empty */
bool InsertFirstNode( int value );
关键是,您应该隐藏所有可以测试的函数中的指针旋转,这样您就可以编写一条可理解的主线,第一次工作:

if( ! InsertFirstNode( value ) )
   InsertAfter( FindLessThan( value ), value );

因为你使用C++,所以你的列表要有一个类和函数成员.< /p> 实现细节:您必须担心特殊情况:新值在head之前或尾部之后。所以我建议使用枚举来处理这些问题

/** Special cases for placing a new node */
enum class eFind
{
    list_empty,         // the list was empty
    before_first,       // the new node goes before the first node in list
    before_node,        // the new node goes before the specified node
    after_last,         // the new node goes after the last node in the list
}; 
/** Find node with smallest value greater than given

    @param[out] place eFind enumeration, one of list_empty,before_first,before_node,after_last
    @param[in] value being inserted

    @return n node before which value should be placed

    Assumes sorted list exist.
*/
Node * FindSmallestGreaterThan( eFind & place, int value )

事实证明,在插入之前比在插入之后更容易(代码更少)。您可以看到在或运行的代码。

1。您无法初始化结构中的成员:

struct List
{
    Node *head;
    Node *tail;
};
2.(a)函数的原型
insertIt
insertNode
是错误的。您正在使用“按引用传递”传递
。应如下所示:

void insertIt(节点*头,节点*尾,int值)

void insertNode(节点*头,节点*尾,int值)

2.(b)
else
部分中创建节点时,应将新节点的
next
prev
指针设置为
NULL

tmp->prev=NULL;
tmp->next=NULL; 
2.(c)当您通过
tail
使用按引用传递时,在
tail
上循环时在内部所做的任何更改都会反映在程序中。因此,请使用
节点类型的临时指针

3.另外,您使用的设计不好。因此,我建议您更改它。这是我对链表的实现:

main()
{
    struct List Q;
    Initialize_list(&Q);
    Insert_it(&Q,12);
}
void Initialize_list(struct List *L)
{
    L->head=NULL;
    L->tail=NULL;
}

1。不能初始化结构中的成员:

struct List
{
    Node *head;
    Node *tail;
};
2.(a)函数的原型
insertIt
insertNode
是错误的。您正在使用“按引用传递”传递
。应如下所示:

void insertIt(节点*头,节点*尾,int值)

void insertNode(节点*头,节点*尾,int值)

2.(b)
else
部分中创建节点时,应将新节点的
next
prev
指针设置为
NULL

tmp->prev=NULL;
tmp->next=NULL; 
2.(c)当您通过
tail
使用按引用传递时,在
tail
上循环时在内部所做的任何更改都会反映在程序中。因此,请使用
节点类型的临时指针

3.另外,您使用的设计不好。因此,我建议您更改它。这是我对链表的实现:

main()
{
    struct List Q;
    Initialize_list(&Q);
    Insert_it(&Q,12);
}
void Initialize_list(struct List *L)
{
    L->head=NULL;
    L->tail=NULL;
}

问题是在
while
循环头中检查
prev->value
。这不会检查
tail->prev!=nullptr
为真。对于
head==tail
valuevalue
的情况,这是一个问题。如果
head!=tail
,您的代码确实可以工作,因为第一次计算
valueprev->value
,即
tail->prev!=nullptr
为true,循环体中的代码将捕获大小写
head->next==tail
。 正确的检查应该是
tail->prev!=nullptr&&valueprev->value
。这首先检查
tail->prev
是否可以解除防护

然后在完成
whil之后,您可以以
tail->prev==nullptr
结束