我正在研究一些定义链表(不使用STL容器)的遗留代码
我想转换此代码以便使用STL列表。正如您在以下示例中所看到的,为链接列表分配了所有N的初始值。然后列表中的某些元素被赋予一些值。然后列表中的“空元素”被“清理”。
我正在寻找一种更好的方法来使用STL。特别是,这可以避免删除空元素代码吗?我检查了STL文档..它定义了一个remove
方法,但这不完全是我需要的。有没有办法动态分配链表大小?我很感激你的建议!
更新 我修改了代码。这类似于我的主要代码。但为了避免任何混淆,我在下面编写一个伪代码来解释它是如何工作的。
步骤
elementIds
分配给链接列表(struct my_list
)meshElem
,我对meshElem->elem
struct中的一些值感兴趣。
elemId = meshElem->elem->id;
此elemId
位于0 to elementIds
范围内。 elemId
将用作索引,以查找struct my_list lst
中的特定元素,例如lst[elemId]
doSomething ()
函数中,循环浏览0 to elementIds
。在此循环中,如果满足某些条件,则为lst->number
分配一个整数值= someArray[i]
,其中i在范围0 to N
中(在appendElement
中完成)next
中没有struct my_list lst
条目的元素会被清理(问题:这可以避免吗?)现在修改后的代码:
struct my_list
{
int number;
struct my_list *prev;
struct my_list *next;
}
void doSomething(void){
const int N = 50000;
const int elementIds = 10000;
int i, elemId, node_i;
struct my_list *lst;
lst = new struct my_list[elementIds];
int someArray[12];
meshElem = mesh->next;
for(i=0; i<=elementIds; i++) {
lst[i].num = 0;
lst[i].next = NIL;
lst[i].prev = NIL;
}
while(meshElem != NIL){
// Element id (int)
// Note that any elemId will be in range [0 - elemId ]
elemId = meshElem->elem->id;
// Do some operations to populate "lst"
// Note that 'lst' gets values ONLY for certain
// values of i
for (i = 0; i<=N; i++){
// if certain conditions are satisfied,
// it updates the linked list element
// lst[meshIdx]. foo1(), foo2() are just some conditions...
if (foo1()){
appendElement(someArray[i], &lst[meshIdx])
}
else if (foo2()){
appendElement(someArray[i], &lst[meshIdx])
}
}
meshElem = meshelem->next;
} // End of while(meshElem != NIL)
// Clean up the linked list lst
// by removing unassigned items.
struct my_list *lst_2
for(i=1; i<=N; i++) {
lst_2 = &lst[i];
while( lst != NIL ) {
if( lst->next != NIL && lst->next->number == 0 ) {
delete lst_2->next;
lst_2->next = NIL;
} // end of if loop
lst = lst_2->next;
} // end of while while( lst != NIL )
} // End of for(i=1; i<=N; i++)
// Do some more stuff that uses struct my_list lst
for(i=1;i<=elementIds;i++) {
while( lst[i] != NIL && (node_i = lst[i]->number) ) {
if( node_i == 0) {
lst[i] = lst[i]->next;
continue;
}
// Use this "node_i" index in some other arrays to
// do more stuff.
//..
//..
//..
lst[i] = lst[i]->next;
}
}
void appendElement(int n, struct my_list *lst) {
int exists = 0;
while( lst->next != NIL ) {
if( lst->number == n ) {
exists = 1;
lst=lst->next;
}
if( exists < 1 ) {
lst->number = n2;
insertElemAfter(lst, 0);
}
}
答案 0 :(得分:7)
您的旧链表实际上是一个线程稀疏向量。具有NULL的数组是稀疏向量,链接列表提供线程。这两个组合可以持续访问各个节点(随机访问数组)和有效遍历“有效”节点(避免使用NULL)。
假设这两个方面都很重要,并且假设数据可能比您显示的简单int更复杂,那么您可以创建一个数据结构,例如:
class ThreadedSparseVector {
private:
std::vector<Data*> m_thread;
std::vector<int> m_sparse_vector;
};
在初始化期间,您可以预先调整m_sparse_vector的大小并将值初始化为-1。在追加元素(或访问它们)时,首先检查它是否已经“有效”,如果不是,则将其添加到线程中:
void ThreadedSparseVector::appendElement(int i) {
if (-1 == m_sparse_vector[i]) {
// Add new data
m_sparse_vector[i] = m_thread.size()
m_thread.push_back(new Data(i));
}
Data* data = m_thread[m_sparse_vector[i]];
// Initialize/update data as necessary
}
如果线程比随机访问更重要,另一种选择是简单地使用STL映射。如果随机访问比线程更重要,那么您可以简单地使用STL向量并在迭代期间容忍NULL(或创建自动跳过NULL的自定义迭代器)。
另一种选择,取决于您转换为STL的动机,是创建一个包含实现STL兼容接口的遗留代码的包装器,而不是将数据结构本身转换为使用STL。
答案 1 :(得分:1)
链表通常不使用连续内存,而是使用碎片堆分配的节点。我想如果你为std::list
构造函数提供一个初始计数,那么至少有很多节点是连续的。除此之外,您需要编写自己的分配器以与std::list
一起使用。
答案 2 :(得分:0)
struct my_list {
int number;
}
void doSomething(void){
std::list<my_list> lst;
const int N = 10000;
for (int i = 0; i<=N; ++i) {
if (1 == foo(N)) { //I'm guessing this is what you meant
my_list new_element; //Initalize with something;
lst.push_back(new_element);
}
}
}
int
foo(int n) {
// some function that returns 0 or 1 based on
// the value of n
return 1;
}
答案 3 :(得分:0)
std::list<int> lst;
答案 4 :(得分:0)
在你的逻辑中,不是在开始时创建所有节点,为什么不运行循环一次并为真实条件动态创建一个元素并将其添加到列表中。
for (i = 0; i<=N; i++)
{
if ( i == foo(N) )
node = createNode();
appendElement(node);
}
答案 5 :(得分:0)
我想你只是想:
std::list<int> lst;
for (i = 0; i<=N; i++){
if ( i == foo(N) )
lst.push_back(/*some new value*/);
}