我正在尝试创建已排序的链接列表=在创建它时对其进行排序。想法很简单,插入一个节点 - 并检查先前是否较小,如果是,请检查之前的情况,依此类推,直到找到它的位置。我创建了这段代码。
struct Node{
Node *prev;
Node *next;
int value;
};
struct List{
Node *head = nullptr;
Node *tail = nullptr;
};
在这里,我创建了一个节点,以及list的“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;
}
此函数检查list是否为空,如果是,则将节点插入head和tail(例如head = tail =列表中只有一个节点);
让我烦恼的是插入节点的功能
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;
}
}
}
如果list为空,则调用insertNode()
,如果节点的值小于上一个节点的值,则会抓取列表以查找其位置。
此片段代码仅在插入的第一个节点也是最小节点时才有效。 e.g
insertIt(list.head , list.tail , -1);
insertIt(list.head , list.tail , 0);
insertIt(list.head , list.tail , 7);
insertIt(list.head , list.tail , 1);
insertIt(list.head , list.tail , 2);
insertIt(list head , list.tail , 2);
工作,如果我打印列表,它是很好的排序。但
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;
}
这将检查节点是否为头,并与新节点交换头,使新节点成为新节点。
为什么会崩溃代码?我没有找到合理的答案。另外,我怎样才能改进我的“算法”以使其更有效?
答案 0 :(得分:2)
您想要做两件事:在列表中找到新节点所在的位置并在一个位置插入新节点。所以,编写两个函数,一个执行每个任务。然后,您可以在集成之前单独测试和调试它们。这将更加直截了当。进一步的推荐:在实现功能之前,为每个功能编写单元测试。
/** 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 ++,因此请将列表作为类和函数成员。
实施细节:您必须担心特殊情况:新值在头部之前或尾部之后。所以我建议使用枚举来处理这些。
/** 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 )
使用InsertBefore而不是InsertAfter也更容易(更少的代码)。您可以在cpp.sh/4xitp或github gist
看到代码答案 1 :(得分:2)
当遍历列表以找到插入新节点的位置时,您可以执行以下操作:
tail = tail -> prev;
但tail
变量由引用传递,即修改yout tail
对象的List
成员,从而破坏其一致性。< / p>
使用另一个名为current
或position
的临时变量来遍历列表,除非您在末尾添加新节点,否则不要修改tail
清单。
编辑示例方法
struct Node {
Node(int val);
Node *prev;
Node *next;
int value;
};
struct List{
List() : head(nullptr), tail(nullptr) {}
void insert(int value);
Node *head;
Node *tail;
};
Node::Node(int val) :
value(val), next(nullptr), prev(nullptr)
{
}
void List::insert(int value) {
Node *tmp = new Node(value);
if(head == nullptr) {
head = tmp;
tail = tmp;
return;
}
Node *pos; // find the node greater or equal to 'value'
for(pos = head; pos && pos->value < value; pos = pos->next)
;
if(pos) { // appropriate pos found - insert before
tmp->next = pos;
tmp->prev = pos->prev;
tmp->next->prev = tmp;
if(tmp->prev) // there is some predecessor
tmp->prev->next = tmp;
else
head = tmp; // making a new first node
} else { // pos not found - append at the end
tmp->next = nullptr;
tmp->prev = tail;
tail->next = tmp;
tail = tmp;
}
}
答案 2 :(得分:1)
1。您无法初始化结构内的成员:
struct List
{
Node *head;
Node *tail;
};
2.(a)函数原型insertIt
和insertNode
是错误的。您使用传递引用传递head
和tail
它应该如下:
void insertIt(Node * head ,Node * tail ,int value)
void insertNode(Node * head,Node * tail,int value)
2.(b)在else
部分创建节点时,应将新节点的next
和prev
指针设置为{{ 1}}:
NULL
2.(c)正如您通过引用传递tmp->prev=NULL;
tmp->next=NULL;
时所做的任何更改,而tail
上的循环都反映在program.Hence中使用临时指针类型为tail
。
3。此外,您使用的设计并不好。我建议您更改它。这是我对链表的实现:
Node
答案 3 :(得分:1)
问题是value < tail->prev->value
循环头中的while
检查。这不会检查tail->prev != nullptr
是否为真。对于head == tail
和value < head->value
的情况,这是一个问题。如果head != tail
,您的代码确实有效,因为第一次评估value < tail->prev->value
时,tail->prev != nullptr
为真,并且案例head->next == tail
将被循环体中的代码捕获。
正确的检查将是tail->prev != nullptr && value < tail->prev->value
。首先检查tail->prev
是否可以解除反对。
然后,在完成tail->prev == nullptr
循环后(由于新条件),您可能会以while
结束。检查可以移出循环,导致以下代码:
while (tail->prev != nullptr && value < tail->prev->value) {
tail = tail->prev;
}
if (tail->prev == nullptr) {
// Prepend node to the list
return;
}
// Insert node in front of tail
编辑:您仍然可以检查循环中的条件tail->prev == nullptr
;循环之后的检查只对捕获案例head == tail && value < head->value
有用。不在循环中进行检查具有更短和(在我看来)模式可读代码的好处。
答案 4 :(得分:0)
这可能是您正在寻找的代码;-)您可以在VS2013中按原样运行它。它将插入函数简化为几个if语句。并且可以通过使用头部和头部的终端元件进一步简化。尾。
我希望这会有所帮助: - )
struct Node
{
int value; Node *prev, *next;
};
struct DoublyLinkedSortedList
{
Node *head = nullptr, *tail = nullptr;
void insert(int value)
{
// Find first node bigger then the new element, or get to the end of the list
Node* node = head;
while (node && node->value <= value) { node = node->next; }
// Once found, insert your new element before the currently pointed node, or at the end of the list
node = new Node{ value, node?node->prev:tail, node };
if (node->prev) node->prev->next = node; else head = node;
if (node->next) node->next->prev = node; else tail = node;
}
};
#include <climits>
#include <iostream>
using namespace std;
int main()
{
cout << "This is a DoublyLinkedList test." << endl << endl;
// test the list
DoublyLinkedSortedList list;
list.insert(234);
list.insert(INT_MIN);
list.insert(17);
list.insert(1);
list.insert(INT_MAX);
list.insert(-34);
list.insert(3);
list.insert(INT_MAX);
list.insert(INT_MIN);
list.insert(9);
list.insert(7);
// print nodes in order;
cout << "This are the contents of the linked list front to back" << endl << endl;
for (Node* curr = list.head; curr != nullptr; curr = curr->next) { cout << curr->value << "; "; }
cout << endl << endl << "This are the contents of the linked list back to front" << endl << endl;
for (Node* curr = list.tail; curr != nullptr; curr = curr->prev) { cout << curr->value << "; "; }
cout << endl << endl;
system("pause");
}