Сохранение указателя на последний узел в двусвязном списке при выполнении сортировки вставкой - PullRequest
0 голосов
/ 27 мая 2018

Здесь у меня есть файл заголовка для включения функций:

#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 голосов
/ 01 июня 2018

Обычно гораздо проще использовать сторожевой узел, чем NULL, чтобы указать конец списка.Таким образом, пустой список состоит из узла, голова и хвост которого указывают на себя.После добавления элементов sentinel-> next является первым в списке, а sentinel-> 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);
0 голосов
/ 27 мая 2018

Со списками, это помогает нарисовать диаграмму для всех случаев.Естественно использовать индукцию в списках для проверки правильности кода.

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

* В идеале можно было бы освободить память при выходе.

...