双链表:交换功能并不总是有效

时间:2019-12-06 15:54:24

标签: c list

我已经编写了这段代码,总体上效果不错,但是当我们到达i == 74列表元素为4 - 11 - 18 - 4 - 10 - 18 - 17 - 22 - 14 - 29swapNodes()函数必须用键18交换两个节点,但是我得到了以下元素:4 - 18 - 4 - 10 - 18 - 17 - 22 - 14 - 29。我尝试使用“交换”之前的确切值初始化列表,然后尝试交换这两个节点,一切正常。

PS:如果有人可以帮助我用更少的行来编写swapNodes()函数,我将不胜感激,但是目前这不是必需的。

typedef struct _node{
    int key;
    struct _node *next;
    struct _node *prev;
}node;

node* createNode(int key){
    node* a = (node*)malloc(sizeof(struct _node));
    a->key = key;
    a->next = NULL;
    a->prev = NULL;
    return a;
}

void printList(node* head){
    while (head != NULL){
        printf("%d", head->key);
        if(head->next != NULL) printf(" - ");
        head = head->next;
    }
    printf("\n");
}

void fillList(node** head, int dim){
    int i;
    for(i=0; i<dim; i++)
        listInsert(head, createNode(rand()%30));
}

//findes a node given an index, the indices start from 1
node** findNode(node** head, int index){
    int i;
    for(i=1; i<index; i++)
        head = &(*head)->next;
    if(head != NULL) return head;
    else return NULL;
}

void listInsert(node** head, node* node){
    if((*head) == NULL){
        (*head) = node;
        return;
    }
    node->next = (*head);
    (*head)->prev = node;
    (*head) = node;
}

int main(){
    node* list = NULL;
    fillList(&list, 10);
    int i, a, b;
    for(i=0; i<100; i++){
        printList(list);
        a = rand()%10 +1;
        b = rand()%10 +1;
        swapNodes(&list, *findNode(&list, a), *findNode(&list, b));
        printList(list);
        printf("\n");
    }
    return 0;
}

编辑:

我设法重写了swapNodes()函数,但是这次在main中执行相同的行,因此在i==15a==4b==2的列表中得到一个循环。再次,如果我尝试手动交换任何节点,该功能将正常工作。

void swapNodes(node** head, node* a, node* b){
    node* aPrev = a->prev;
    node* aNext = a->next;
    node* bPrev = b->prev;
    node* bNext = b->next;
    if(a == b) return;
    if(a->prev == b || 
    (b->prev == NULL && a->next == NULL) || 
    (b->prev == NULL && b->next == a) || 
    a->next == NULL) return swapNodes(head, b, a);
    if(a->prev == NULL)
        (*head) = b;
    else if(b->prev == NULL)
        (*head) = a;

    if(a->next == b){
        if(aPrev != NULL) aPrev->next = b;
        b->prev = aPrev;
        b->next = a;
        bNext->prev = a;
        a->prev = b;
        a->next = bNext;
    }else{
        b->next = aNext;
        a->next = bNext;

        if(a->prev != NULL)
            aPrev->next = b;
        if(b->prev != NULL)
            bPrev->next = a;

        if(a->next != NULL)
            aNext->prev = b;
        if(bNext != NULL)
            bNext->prev = a;

        if(b != NULL)
            b->prev = aPrev;
        if(a != NULL)
            a->prev = bPrev;
    }
}

1 个答案:

答案 0 :(得分:0)

遵循@ggorlen给我的想法,我重新编写了swapNodes()函数,并添加了一些新函数,最后它完美地工作了。为了在提取节点之前跟踪节点的位置,我创建了一个struct,其中包含从findIndex()函数返回的索引和节点本身。我还更改了findNode()函数,以便它返回类型为node*而不是node**的变量。当然不是很有效,但是我会做的。

typedef struct _extractedNode{
    struct _node* node;
    int index;
}extractedNode;

int findIndex(node* head, node* node){
    int i=1;
    node* temp = head;
    while(node != temp){
        temp = temp->next;
        i++;
    }
    return i;
}

extractedNode extractNode(node** head, node* node){
    extractedNode extracted;
    extracted.index = 0;
    if(node == NULL){
        printf("extractNode(): il nodo non esiste!\n");
        extracted.node = NULL;
        extracted.index = -1;
    }else{
        node* prev = node->prev;
        node* next = node->next;
        if(prev == NULL){
            (*head) = next;
            extracted.index = 1;
        }
        if(extracted.index != 1)
            extracted.index = findIndex(*head, node);
        if(prev != NULL)
            prev->next = next;
        if(next != NULL)
            next->prev = prev;
        node->next = NULL;
        node->prev = NULL;
        extracted.node = node;
    }
    return extracted;
}

void listInsertAsIndex(node** head, int index, node* node){
    if(index <= 0) return;
    if(index == 1) return listInsert(head, node);
    else{
        node* prev = findNode(*head, index-1);
        node* next = prev->next;
        prev->next = node;
        node->prev = prev;
        if(next != NULL){
            node->next = next;
            next->prev = node;
        }
    }
}

void swapNodes(node** head, node* a, node* b){
    if(a == b) return;
    extractedNode aX, bX;
    if(a->prev == NULL && a->next == b){
        aX = extractNode(head, a);
        listInsertAsIndex(head, 2, aX.node);
    }else if(b->prev == NULL && b->next == a){
        bX = extractNode(head, b);
        listInsertAsIndex(head, 2, bX.node);
    }else if(a->next == b){
        aX = extractNode(head, a);
        listInsertAsIndex(head, aX.index +1, aX.node);
    }else if(b->next == a){
        bX = extractNode(head, b);
        listInsertAsIndex(head, bX.index +1, bX.node);
    }else{
        aX = extractNode(head, a);
        bX = extractNode(head, b);
        if(aX.index < bX.index){
            listInsertAsIndex(head, aX.index, bX.node);
            listInsertAsIndex(head, bX.index +1, aX.node);
        }else{
            listInsertAsIndex(head, bX.index, aX.node);
            listInsertAsIndex(head, aX.index, bX.node);
        }
    }
}