- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个以下类型的对象数组:
struct Node {
Node *_pPrev, *_pNext;
double *_pData;
};
一些节点参与双向链表,_pData!=nullptr
用于此类节点。还有一个虚拟头节点,其中 _pNext
指向列表的开头,_pPrev
指向结尾。该列表以仅包含此头节点开始,并且永远不应将其从列表中删除。
双向链表由一个数组支持,初始大小等于列表中的最大节点数。
struct Example {
Node _nodes[MAXN];
Node _head;
};
现在我想对该数据结构执行以下操作:给定 _nodes
数组的 2 个索引 i
和 j
,交换数组中的节点,但保留它们在双向链表中的位置。此操作需要更新 _nodes[i]._pPrev->_pNext
、_nodes[i]._pNext->_pPrev
和节点 j
相同.
一个问题是当节点 i
和 j
彼此相邻时的极端情况。另一个问题是天真的代码涉及很多if
(检查每个节点的_pData==nullptr
并以不同方式处理3种情况,并检查是否节点彼此相邻),从而变得低效。
如何高效地做到这一点?
这是我目前在 C++ 中的内容:
assert(i!=j);
Node &chI = _nodes[i];
Node &chJ = _nodes[j];
switch (((chI._pData == nullptr) ? 0 : 1) | ((chJ._pData == nullptr) ? 0 : 2)) {
case 3:
if (chI._pNext == &chJ) {
chI._pPrev->_pNext = &chJ;
chJ._pNext->_pPrev = &chI;
chI._pNext = &chI;
chJ._pPrev = &chJ;
}
else if (chJ._pNext == &chI) {
chJ._pPrev->_pNext = &chI;
chI._pNext->_pPrev = &chJ;
chJ._pNext = &chJ;
chI._pPrev = &chI;
} else {
chI._pNext->_pPrev = &chJ;
chJ._pNext->_pPrev = &chI;
chI._pPrev->_pNext = &chJ;
chJ._pPrev->_pNext = &chI;
}
break;
case 2:
chJ._pNext->_pPrev = &chI;
chJ._pPrev->_pNext = &chI;
break;
case 1:
chI._pNext->_pPrev = &chJ;
chI._pPrev->_pNext = &chJ;
break;
default:
return; // no need to swap because both are not in the doubly-linked list
}
std::swap(chI, chJ);
最佳答案
这是先交换后修复 (TM) 方法的说明。它的主要功绩是避免了所有极端情况。它确实假设了一个格式良好的 LL ,并且忽略了“in_use”条件(恕我直言,该条件与 LL 交换问题正交)
请注意,我做了一些重命名,添加了测试数据,并转换为纯 C。
已编辑(现在它真的有效了!)
#include <stdio.h>
struct Node {
struct Node *prev, *next;
// double *_pData;
int val;
};
#define MAXN 5
struct Example {
struct Node head;
struct Node nodes[MAXN];
};
/* sample data */
struct Example example = {
{ &example.nodes[4] , &example.nodes[0] , -1} // Head
,{ { &example.head , &example.nodes[1] , 0}
, { &example.nodes[0] , &example.nodes[2] , 1}
, { &example.nodes[1] , &example.nodes[3] , 2}
, { &example.nodes[2] , &example.nodes[4] , 3}
, { &example.nodes[3] , &example.head , 4}
}
};
void swapit( unsigned one, unsigned two)
{
struct Node tmp, *ptr1, *ptr2;
/* *unique* array of pointers-to pointer
* to fixup all the references to the two moved nodes
*/
struct Node **fixlist[8];
unsigned nfix = 0;
unsigned ifix;
/* Ugly macro to add entries to the list of fixups */
#define add_fixup(pp) fixlist[nfix++] = (pp)
ptr1 = &example.nodes[one];
ptr2 = &example.nodes[two];
/* Add pointers to some of the 8 possible pointers to the fixup-array.
** If the {prev,next} pointers do not point to {ptr1,ptr2}
** we do NOT need to fix them up.
*/
if (ptr1->next == ptr2) add_fixup(&ptr2->next); // need &ptr2->next here (instead of ptr1)
else add_fixup(&ptr1->next->prev);
if (ptr1->prev == ptr2) add_fixup(&ptr2->prev); // , because pointer swap takes place AFTER the object swap
else add_fixup(&ptr1->prev->next);
if (ptr2->next == ptr1) add_fixup(&ptr1->next);
else add_fixup(&ptr2->next->prev);
if (ptr2->prev == ptr1) add_fixup(&ptr1->prev);
else add_fixup(&ptr2->prev->next);
fprintf(stderr,"Nfix=%u\n", nfix);
for(ifix=0; ifix < nfix; ifix++) {
fprintf(stderr, "%p --> %p\n", fixlist[ifix], *fixlist[ifix]);
}
/* Perform the rough swap */
tmp = example.nodes[one];
example.nodes[one] = example.nodes[two];
example.nodes[two] = tmp;
/* Fixup the pointers, but only if they happen to point at one of the two nodes */
for(ifix=0; ifix < nfix; ifix++) {
if (*fixlist[ifix] == ptr1) *fixlist[ifix] = ptr2;
else *fixlist[ifix] = ptr1;
}
}
void dumpit(char *msg)
{
struct Node *ptr;
int i;
printf("%s\n", msg);
ptr = &example.head;
printf("Head: %p {%p,%p} %d\n", ptr, ptr->prev, ptr->next, ptr->val);
for (i=0; i < MAXN; i++) {
ptr = example.nodes+i;
printf("# %u # %p {%p,%p} %d\n", i, ptr, ptr->prev, ptr->next, ptr->val);
}
}
int main(void)
{
dumpit("Original");
swapit(1,2);
dumpit("After swap(1,2)");
swapit(0,1);
dumpit("After swap(0,1)");
swapit(0,2);
dumpit("After swap(0,2)");
swapit(0,4);
dumpit("After swap(0,4)");
return 0;
}
为了说明我们可以忽略 in_use
条件这一事实,这是一个新版本,在同一个数组中有两个 双链表。这可能是一个in_use 列表和广告免费 列表。
#include <stdio.h>
struct Node {
struct Node *prev, *next;
// double *_pData;
// int val;
char * payload;
};
#define MAXN 8
struct Example {
struct Node head;
struct Node free; /* freelist */
struct Node nodes[MAXN];
};
/* sample data */
struct Example example = {
{ &example.nodes[5] , &example.nodes[0] , ""} /* Head */
, { &example.nodes[6] , &example.nodes[2] , ""} /* freelist */
/* 0 */ ,{ { &example.head , &example.nodes[1] , "zero"}
, { &example.nodes[0] , &example.nodes[3] , "one"}
, { &example.free , &example.nodes[6] , NULL }
, { &example.nodes[1] , &example.nodes[4] , "two"}
/* 4 */ , { &example.nodes[3] , &example.nodes[5] , "three"}
, { &example.nodes[4] , &example.head , "four"}
, { &example.nodes[2] , &example.free , NULL}
, { &example.nodes[7] , &example.nodes[7] , "OMG"} /* self referenced */
}
};
void swapit( unsigned one, unsigned two)
{
struct Node tmp, *ptr1, *ptr2;
/* *unique* array of pointers-to pointer
* to fixup all the references to the two moved nodes
*/
struct Node **fixlist[4];
unsigned nfix = 0;
unsigned ifix;
/* Ugly macro to add entries to the list of fixups */
#define add_fixup(pp) fixlist[nfix++] = (pp)
ptr1 = &example.nodes[one];
ptr2 = &example.nodes[two];
/* Add pointers to some of the 4 possible pointers to the fixup-array.
** If the {prev,next} pointers do not point to {ptr1,ptr2}
** we do NOT need to fix them up.
** Note: we do not need the tests (.payload == NULL) if the linked lists
** are disjunct (such as: a free list and an active list)
*/
if (1||ptr1->payload) { /* This is on purpose: always True */
if (ptr1->next == ptr2) add_fixup(&ptr2->next); // need &ptr2->next here (instead of ptr1)
else add_fixup(&ptr1->next->prev);
if (ptr1->prev == ptr2) add_fixup(&ptr2->prev); // , because pointer swap takes place AFTER the object swap
else add_fixup(&ptr1->prev->next);
}
if (1||ptr2->payload) { /* Ditto */
if (ptr2->next == ptr1) add_fixup(&ptr1->next);
else add_fixup(&ptr2->next->prev);
if (ptr2->prev == ptr1) add_fixup(&ptr1->prev);
else add_fixup(&ptr2->prev->next);
}
fprintf(stderr,"Nfix=%u\n", nfix);
for(ifix=0; ifix < nfix; ifix++) {
fprintf(stderr, "%p --> %p\n", fixlist[ifix], *fixlist[ifix]);
}
/* Perform the rough swap */
tmp = example.nodes[one];
example.nodes[one] = example.nodes[two];
example.nodes[two] = tmp;
/* Fixup the pointers, but only if they happen to point at one of the two nodes */
for(ifix=0; ifix < nfix; ifix++) {
if (*fixlist[ifix] == ptr1) *fixlist[ifix] = ptr2;
else *fixlist[ifix] = ptr1;
}
}
void dumpit(char *msg)
{
struct Node *ptr;
int i;
printf("%s\n", msg);
ptr = &example.head;
printf("Head: %p {%p,%p} %s\n", ptr, ptr->prev, ptr->next, ptr->payload);
ptr = &example.free;
printf("Free: %p {%p,%p} %s\n", ptr, ptr->prev, ptr->next, ptr->payload);
for (i=0; i < MAXN; i++) {
ptr = example.nodes+i;
printf("# %u # %p {%p,%p} %s\n", i, ptr, ptr->prev, ptr->next, ptr->payload);
}
}
int main(void)
{
dumpit("Original");
swapit(1,2); /* these are on different lists */
dumpit("After swap(1,2)");
swapit(0,1);
dumpit("After swap(0,1)");
swapit(0,2);
dumpit("After swap(0,2)");
swapit(0,4);
dumpit("After swap(0,4)");
swapit(2,5); /* these are on different lists */
dumpit("After swap(2,5)");
return 0;
}
关于algorithm - 通过后备数组中的索引交换双向链表中的项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39613508/
我想做的是让 JTextPane 在 JPanel 中占用尽可能多的空间。对于我使用的 UpdateInfoPanel: public class UpdateInfoPanel extends JP
我在 JPanel 中有一个 JTextArea,我想将其与 JScrollPane 一起使用。我正在使用 GridBagLayout。当我运行它时,框架似乎为 JScrollPane 腾出了空间,但
我想在 xcode 中实现以下功能。 我有一个 View Controller 。在这个 UIViewController 中,我有一个 UITabBar。它们下面是一个 UIView。将 UITab
有谁知道Firebird 2.5有没有类似于SQL中“STUFF”函数的功能? 我有一个包含父用户记录的表,另一个表包含与父相关的子用户记录。我希望能够提取用户拥有的“ROLES”的逗号分隔字符串,而
我想使用 JSON 作为 mirth channel 的输入和输出,例如详细信息保存在数据库中或创建 HL7 消息。 简而言之,输入为 JSON 解析它并输出为任何格式。 最佳答案 var objec
通常我会使用 R 并执行 merge.by,但这个文件似乎太大了,部门中的任何一台计算机都无法处理它! (任何从事遗传学工作的人的附加信息)本质上,插补似乎删除了 snp ID 的 rs 数字,我只剩
我有一个以前可能被问过的问题,但我很难找到正确的描述。我希望有人能帮助我。 在下面的代码中,我设置了varprice,我想添加javascript变量accu_id以通过rails在我的数据库中查找记
我有一个简单的 SVG 文件,在 Firefox 中可以正常查看 - 它的一些包装文本使用 foreignObject 包含一些 HTML - 文本包装在 div 中:
所以我正在为学校编写一个 Ruby 程序,如果某个值是 1 或 3,则将 bool 值更改为 true,如果是 0 或 2,则更改为 false。由于我有 Java 背景,所以我认为这段代码应该有效:
我做了什么: 我在这些账户之间创建了 VPC 对等连接 互联网网关也连接到每个 VPC 还配置了路由表(以允许来自双方的流量) 情况1: 当这两个 VPC 在同一个账户中时,我成功测试了从另一个 La
我有一个名为 contacts 的表: user_id contact_id 10294 10295 10294 10293 10293 10294 102
我正在使用 Magento 中的新模板。为避免重复代码,我想为每个产品预览使用相同的子模板。 特别是我做了这样一个展示: $products = Mage::getModel('catalog/pro
“for”是否总是检查协议(protocol)中定义的每个函数中第一个参数的类型? 编辑(改写): 当协议(protocol)方法只有一个参数时,根据该单个参数的类型(直接或任意)找到实现。当协议(p
我想从我的 PHP 代码中调用 JavaScript 函数。我通过使用以下方法实现了这一点: echo ' drawChart($id); '; 这工作正常,但我想从我的 PHP 代码中获取数据,我使
这个问题已经有答案了: Event binding on dynamically created elements? (23 个回答) 已关闭 5 年前。 我有一个动态表单,我想在其中附加一些其他 h
我正在尝试找到一种解决方案,以在 componentDidMount 中的映射项上使用 setState。 我正在使用 GraphQL连同 Gatsby返回许多 data 项目,但要求在特定的 pat
我在 ScrollView 中有一个 View 。只要用户按住该 View ,我想每 80 毫秒调用一次方法。这是我已经实现的: final Runnable vibrate = new Runnab
我用 jni 开发了一个 android 应用程序。我在 GetStringUTFChars 的 dvmDecodeIndirectRef 中得到了一个 dvmabort。我只中止了一次。 为什么会这
当我到达我的 Activity 时,我调用 FragmentPagerAdapter 来处理我的不同选项卡。在我的一个选项卡中,我想显示一个 RecyclerView,但他从未出现过,有了断点,我看到
当我按下 Activity 中的按钮时,会弹出一个 DialogFragment。在对话框 fragment 中,有一个看起来像普通 ListView 的 RecyclerView。 我想要的行为是当
我是一名优秀的程序员,十分优秀!