【问题标题】:How to Properly Use a Direction Switch in a Doubly Linked List?如何在双向链表中正确使用方向开关?
【发布时间】:2020-07-05 12:30:28
【问题描述】:

我有一个双向链表,我想改变链表的方向。例如:

1 -> 2 -> 3

变成

3 -> 2 -> 1

我在结构中使用了布尔表达式来确定方向。

typedef struct Node Node;

struct Node {
char character;
Node *link[2];
bool dir;
} direction;

我用这种格式确定方向:

Node *p;
p->link[p->dir];

Node *p;
p->link[!p->dir];

我遇到的问题是我想使用使用 O(1) 运行时的方法来翻转这些布尔方向。我试图构建一个像这样处理它的函数:

//global variable
int d = 0;

//function
void switchStack ( ) {
    if (d == 0) {
        d = 1;
        direction->link[direction->dir] = direction->link[!direction->dir];
    else if (d == 1) {
        d = 0;
        direction->link[direction->dir] = direction->link[!direction->dir];
    }

这个函数似乎没有做任何事情,当我调用它时,我尝试的任何其他变体都会使程序崩溃。有人知道如何正确使用方向开关来反转运行时间为 0(1) 的堆栈吗?

【问题讨论】:

  • 为什么要把dir放在节点本身中?使用 DLink 列表,您可以将 dir 作为参数传递给所有遍历函数,并且不需要在 each 节点中翻转它[这看起来很浪费而且没有必要]?你真正想做什么?如果您想传递“自我描述”的列表,我会创建一个列表结构(例如)typedef struct list { Node *head; Node *tail; int dir; } List 并将方向标志放在那里
  • @CraigEstey 我正在尝试创建一个可以完全翻转链表顺序或翻转堆栈的函数。我想找到一种方法,用一个函数使堆栈以 O(1) 的运行时间翻转。 “你不需要翻转每个节点”是什么意思?
  • 您的代码以 O(n) 翻转。使用列表结构,您只需执行list->dir = ! list->dir 即可获得 O(1)。看来您实际上并不想更改链接指针???无论您是向前遍历(例如headtail)还是向后遍历(例如tailhead)?
  • @CraigEstey 我确实想更改链接指针所代表的内容。例如,我希望在使用函数时将 true 变为 false,反之亦然。
  • 但老实说,我很难看到双向链表的情况,当您只想选择遍历顺序时,实际上需要对节点进行任何重新排序。跨度>

标签: c big-o doubly-linked-list


【解决方案1】:

这是由我/最顶级的 cmets 开头的。

我仍然不确定你想要什么。但是,这与我能猜到的一样接近。

listadd总是附加到列表的尾部(即它忽略dir)。

但是,listprint 尊重 dir。它是您可以编写的其他函数的模型。

但是,我认为只有listprint 需要查看dir。所有其他函数都可以将给定列表视为转发列表(即查看 listadd 的工作原理)。

#include <stdio.h>
#include <stdlib.h>

typedef struct node Node;
struct node {
    Node *links[2];
    int value;
};
#define PREV    0
#define NEXT    1

typedef struct {
    Node *begend[2];
    int dir;
} List;
#define HEAD    0
#define TAIL    1

static inline Node *
listfirst(List *list)
{
    return list->begend[list->dir ? TAIL : HEAD];
}

static inline Node *
listlast(List *list)
{
    return list->begend[list->dir ? HEAD : TAIL];
}

static inline Node *
nodenext(List *list,Node *cur)
{
    return cur->links[list->dir ? PREV : NEXT];
}

static inline Node *
nodeprev(List *list,Node *cur)
{
    return cur->links[list->dir ? NEXT : PREV];
}

List *
listnew(void)
{
    List *list = calloc(1,sizeof(List));

    return list;
}

Node *
nodenew(int value)
{
    Node *cur = calloc(1,sizeof(Node));

    cur->value = value;

    return cur;
}

void
listadd(List *list,int value)
{
    Node *node = nodenew(value);
    Node *prev = list->begend[TAIL];

    do {
        if (prev != NULL) {
            prev->links[NEXT] = node;
            node->links[PREV] = prev;
            break;
        }

        list->begend[HEAD] = node;
    } while (0);

    list->begend[TAIL] = node;
}

void
listprint(List *list)
{
    Node *cur;

    for (cur = listfirst(list);  cur != NULL;  cur = nodenext(list,cur))
        printf("%d\n",cur->value);
}

int
main(void)
{
    List *list = listnew();

    listadd(list,1);
    listadd(list,2);
    listadd(list,3);

    printf("\n");
    printf("list in forward direction\n");
    listprint(list);

    // reverse the list
    list->dir = ! list->dir;

    printf("\n");
    printf("list in reverse direction\n");
    listprint(list);

    return 0;
}

这是程序的输出:

list in forward direction
1
2
3

list in reverse direction
3
2
1

【讨论】:

  • 如果这不是你想要的,我认为你必须真正考虑你需要什么,你可以修改我发布的内容,或者重写你现有的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-16
  • 2019-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多