C++ 插入节点时对链表排序
我正在尝试创建排序链表=在创建时对其排序。想法很简单,插入一个节点,然后检查previous是否较小,如果较小,则检查previous的previous,依此类推,直到找到它的位置。我已经创建了这段代码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; }; 在这里,我创建了一个节点和列表
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
结束