我在从跳过列表中删除节点时遇到一些问题。我有以下结构:
struct Node
{
int info;
Node **link_;
Node(int v, int levels)
{
info = v;
link_ = new Node*[levels];
for ( int i = 0; i < levels; ++i )
link_[i] = NULL;
}
};
struct List
{
int H; // list height
Node *Header;
List()
{
Header = new Node(0, maxH);
H = 1;
}
};
我认为,问题在于搜索具有给定值的节点然后将其删除的函数。该功能实现如下:
void Remove(int v, List *L)
{
Node *current = L->Header;
for ( int i = L->H - 1; i >= 0; --i )
{
for ( ; current->link_[i] != NULL; current = current->link_[i] )
if ( current->link_[i]->info > v )
break;
else if ( current->link_[i]->info == v )
{
// Node *del = current->link_[i];
current->link_[i] = current->link_[i]->link_[i];
// delete del;
break;
}
}
}
该函数可以正常工作,但是如果我取消注释两条注释行,列表似乎会中断。休息时我的意思是以下测试代码永远不会完成:
int main()
{
srand((unsigned)time(0));
List *SKL = new List();
for ( int i = 0; i < 1000000; ++i )
Insert(rand() * rand(), SKL);
for ( int i = 0; i < 1000000; ++i )
Search(rand() * rand(), SKL);
for ( int i = 0; i < 1000000; ++i )
Remove(rand() * rand(), SKL);
for ( int i = 0; i < 1000000; ++i )
Insert(rand() * rand(), SKL);
return 0;
}
问题在于在列表中插入更多值的最后一个for
循环。如果这两行被注释掉,程序将在大约10秒内完成。如果我取消注释它们,它似乎进入一个无限循环,因为它甚至没有在几分钟内完成。我不确定这是否是从跳过列表中删除节点的正确方法,所以我也发布了我的插入函数:
void Insert(int v, List *L)
{
// this section just determines the levels the new node will be part of
int newH = 0;
int tmp;
unsigned int rnd = rand() * rand();
do
{
tmp = lookup[rnd & 255];
rnd >>= 8;
newH += tmp;
} while ( tmp == 8 );
if ( newH >= L->H )
++L->H;
// this does the actual insertion
Node *newNode = new Node(v, L->H);
Node *current = L->Header;
for ( int i = L->H - 1; i >= 0; --i )
{
for ( ; current->link_[i] != NULL; current = current->link_[i] )
if ( current->link_[i]->info >= v )
break;
if ( i <= newH )
{
newNode->link_[i] = current->link_[i];
current->link_[i] = newNode;
}
}
}
所以,我的问题是:
答案 0 :(得分:2)
正如您猜测的那样,Remove
方法存在问题:
void Remove(int v, List *L)
{
Node *current = L->Header;
for ( int i = L->H - 1; i >= 0; --i )
{
for ( ; current->link_[i] != NULL; current = current->link_[i] )
{
if ( current->link_[i]->info > v )
{
break;
}
else if ( current->link_[i]->info == v )
{
// Node *del = current->link_[i];
current->link_[i] = current->link_[i]->link_[i];
// if (0 == i) delete del;
break;
}
}
}
}
为了举例,我们假设我们要删除的节点出现在2个级别:0和1。
级别for
上的L->H
循环到2没有任何作用。
在第1级,它将找到所请求的节点,并将其删除。
在级别0上,它将尝试跟随指向已删除节点的指针,从而导致未定义的行为。
解决方案:
仅在级别0时删除节点。只要您在上层,该节点仍然被引用,您需要将其保持活动状态。
答案 1 :(得分:0)
在您的删除功能中,您的外部循环遍历列表以获取当前条目数的计数。然后在循环中删除其中一个ntries,但继续迭代旧计数。