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

时间:2018-05-26 23:11:50

标签: 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我无法弄清楚为什么或如何解决这个问题。我该怎么做呢?

2 个答案:

答案 0 :(得分:0)

使用列表,有助于绘制所有案例的图表。在列表上使用归纳来证明您的代码是正确的是很自然的。

#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;
}

*理想情况下,退出时可以释放内存。

答案 1 :(得分:0)

使用sentinel节点而不是NULL来指示列表的结尾通常要简单得多。因此,空列表由头尾指向自身的节点组成。添加元素后,sentinel-&gt; next是列表中的第一个,sentinel-&gt; prev是列表中的最后一个。这将删除您必须在代码中测试NULL的许多情况:

#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* current = top;

    while (current->next != top &&
        current->next->data < newNode->data) {
        current = current->next;
    }

    newNode->next = current->next;
    newNode->next->prev = newNode;

    current->next = newNode;
    current->next->prev = current;
}

void insertionSort(node* top) {
    node* current = top->next;
    // make top an empty ring so can append to it
    top->next = top->prev = top;

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

        sortedInsert(top, current);

        current = next;
    }
}

node* deleteByPos(node* top,int position) {
    int c = 0;
    node* temp = top->next;
    while (true) {
        if (temp == top) {
            printf("Reached end of list, position not available\n\n");
            return top;
        }

        if (c == position) {
            temp->prev->next = temp->next;
            temp->next->prev = temp->prev;
            free(temp);
            return top;
        }

        temp = temp->next;
        c++;
    }
}

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

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

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

#endif /* driver_h */

主文件:

#include "driver.h"

int main() {
    int n;
    node* np;
    node* top;
    top= makeNode(0);

    printf("Enter integers to add to list\n");
    do {
        if (scanf_s("%d", &n) != 1) {
            n = 0;
        }
        if (n != 0) {
            np = makeNode(n);
            np->prev = top->prev;
            top->prev = np;
            top->prev->next = top;
            np->prev->next = np;
        }
    } while (n != 0);