c - 执行插入排序时保存指向双向链表中最后一个节点的指针

标签 c algorithm data-structures insertion-sort

这里我有一个包含函数的头文件:

#ifndef driver_h
#define driver_h

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

typedef struct node node;
typedef struct nodePtrs nodePtrs;

struct node {
    node* next;
    node* prev;
    int data;
};

void sortedInsert(node** top, node* newNode, node** last) {
    node* current;

    if (*top == NULL) {
        *top = newNode;
    } else if ((*top)->data >= newNode->data) {
        newNode->next = *top;
        newNode->next->prev = newNode;
        *top = newNode;
        if ((*top)->next == NULL) {
            *last = *top;
        }
    } else {
        current = *top;
        while (current->next != NULL &&
               current->next->data < newNode->data) {
            current = current->next;
        }

        newNode->next = current->next;

        if (current->next != NULL) {
            newNode->next->prev = newNode;
        }

        current->next = newNode;
        newNode->prev = current;
    }
    if ((*top)->next == NULL) {
        *last = *top;
    }
}

void insertionSort(node** top, node** last) {
    node* sorted = NULL;

    node* current = *top;
    while (current != NULL) {
        node* next = current->next;

        current->prev = current->next = NULL;

        sortedInsert(&sorted, current, last);

        current = next;
    }

    *top = sorted;
}

node* deleteByPos(node* list, node** last, int position) {
    int c = 0;
    node* temp;
    node* prev;

    temp=list;
    if (temp==NULL) {
        printf("No nodes available to delete\n\n");
        return list;
    } else {
        while(temp!=NULL && c != position) {
            prev=temp;
            temp=temp->next;
            c++;
        }
        if (temp==NULL) {
            printf("Reached end of list, position not available\n\n");
            return list;
        } else if (temp->next == NULL) {
            prev->next=temp->next;
            *last = prev;
            free(temp);
            return list;
        } else {
            prev->next=temp->next;
            temp->next->prev = prev;
            free(temp);
            return list;
        }
    }
}

node* makeNode(int n) {
    node* np = malloc(sizeof (node));
    np->data = n;
    np->prev = NULL;
    np->next = NULL;
    return np;
}

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

void printListReverse(node* np) {
    while (np != NULL) {
        printf("%d\n", np->data);
        np = np->prev;
    }
}

#endif /* driver_h */

和一个主文件:

#include "driver.h"

int main() {
    int n;
    node* np;
    node* top;
    node* last;
    printf("Enter integers to add to list\n");
    do {
        if (scanf("%d", &n) != 1) {
            n = 0;
        }
        if (n != 0) {
            np = makeNode(n);
            if (top == NULL) {
                top = np;
            } else {
                last->next = np;
                np->prev = last;
            }
            last = np;
        }
    } while (n != 0);
    printf("\n\n");
    printf("You entered:\n");
    printList(top);
    printf("\n\n");
    printf("In reverse:\n");
    printListReverse(last);
    printf("\n\n");
    printf("Enter a position to delete:");
    scanf("%d", &n);

    top = deleteByPos(top, &last, n);
    printf("\n\n");
    printf("In reverse after delete:\n");
    printListReverse(last);
    insertionSort(&top, &last);
    printf("From top after sort:\n");
    printList(top);
    printf("In reverse after Sort:\n");
    printListReverse(last);
}

这个程序所做的是获取用户输入的整数,将它们存储在双向链表中,删除用户定义点处的节点,然后执行插入排序。我想要做的是使用以下代码在 sortedInsert 函数中保存指向最后一个节点的指针:

if ((*top)->next == NULL) {
   *last = *top;
}

但是,如果你输入 6 5 3 1 9 8 4 2 7 4 2,然后在位置 2 处删除,当反向打印时它会打印出 6 5 4 4 2 2 1。由于某种原因它会跳过 9 7 8 .我不知道为什么或如何解决这个问题。我怎样才能正确地做到这一点?

最佳答案

有了列表,有助于为所有情况绘制图表。很自然地使用列表归纳来证明您的代码是正确的。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h> /* Asserting is useful when it come to lists especially. */

struct node {
    struct node* next;
    struct node* prev;
    int data;
};

/* Saves you from dealing with 'top' and 'tail' every time. */
struct list {
    struct node *head, *tail;
};

/* https://en.wikipedia.org/wiki/Insertion_sort */
void insertionSort(struct list* list) {
    struct node* i = list->head, *j0, *j1;
    while(i) {
        j1 = i, j0 = j1->prev;
        while(j0 && j0->data > j1->data) {
            /* Swap. */
            int temp = j0->data;
            j0->data = j1->data;
            j1->data = temp;
            /* Decrement. */
            j1 = j0;
            j0 = j0->prev;
        }
        i = i->next;
    }
}

/* Returns whether the position was deleted. */
int deleteByPos(struct list* list, int position) {
    struct node* n;

    assert(list);
    /* Node n is the position's in the list. */
    for(n = list->head; n && position; n = n->next, position--);
    if (n==NULL) {
        printf("No nodes available to delete\n\n");
        return 0;
    }
    /* Fixme: If I'm not mistaken, there are 9 cases for you to be
     mathematically certain this works, and I haven't tried them all.
     Eg, 1 node, 2 nodes x2, 3 nodes x3, where the internal node is the 2nd of
     the 3 nodes. */
    if(n->prev == NULL) {
        /* The first one. */
        assert(list->head == n);
        list->head = n->next;
        if(n->next) n->next->prev = NULL;
    } else {
        /* Skip over. */
        n->prev->next = n->next;
    }
    if(n->next == NULL) {
        /* The last one. */
        assert(list->tail == n);
        list->tail = n->prev;
        if(n->prev) n->prev->next = NULL;
    } else {
        /* Skip over. */
        n->next->prev = n->prev;
    }
    n->prev = n->next = NULL; /* Helps in debugging. */
    free(n);
    return 1;
}

struct node* makeNode(struct list *list, int n) {
    struct node* np = malloc(sizeof *np);
    if(!np) return 0;
    np->data = n;
    np->prev = list->tail;
    np->next = NULL;
    /* Push it in the list. */
    if(list->tail) {
        assert(list->head != NULL && list->tail->next == NULL);
        list->tail->next = np;
    } else {
        /* The first one. */
        assert(list->head == NULL && list->tail == NULL);
        list->head = np;
    }
    list->tail = np;
    return np;
}

void printList(const struct list*const list) {
    const struct node *n = list->head;
    while (n) {
        printf("%d\n", n->data);
        n = n->next;
    }
}

void printListReverse(const struct list*const list) {
    const struct node *n = list->tail;
    while (n) {
        printf("%d\n", n->data);
        n = n->prev;
    }
}

int main(void) {
    int n;
    struct list list = { 0, 0 };
    printf("Enter integers to add to list\n");
    while(scanf("%d", &n) == 1 && n)
        if(!makeNode(&list, n)) return perror("node"), EXIT_FAILURE;
    printf("\n\n");
    printf("You entered:\n");
    printList(&list);
    printf("\n\n");
    printf("In reverse:\n");
    printListReverse(&list);
    printf("\n\n");
    printf("Enter a position to delete:");
    scanf("%d", &n);
    printf("You entered %d.\n", n);
    deleteByPos(&list, n);
    printf("\n\n");
    printf("In reverse after delete:\n");
    printListReverse(&list);
    insertionSort(&list);
    printf("From top after sort:\n");
    printList(&list);
    printf("In reverse after Sort:\n");
    printListReverse(&list);
    return EXIT_SUCCESS;
}

*最好在退出时释放内存。

关于c - 执行插入排序时保存指向双向链表中最后一个节点的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50547731/

相关文章:

我们可以省略函数参数的数据类型吗?

c++ - 使用 for_each 和 istream_iterator 遍历 C++ 中的文本文件以查找文件名

algorithm - 使用 Google map 解决旅行商问题的实用方法是什么?

C++ 结构错误 "No matching function for call..."

java - List<Entry<K,V>> - 还有比这更标准的吗?

python - 如何从 Python 脚本访问 C 全局变量

c - 如何编译 Cogl hello 示例

c - 为什么在调用函数时出现“之前的语法错误”?

在 N 个桶中平均分配一组随机整数的算法

python - 列表/字典结构问题