【问题标题】:Saving pointer to last node in doubly linked list when performing insertion sort执行插入排序时保存指向双向链表中最后一个节点的指针
【发布时间】:2018-05-26 23:11:50
【问题描述】:

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

#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 .我不知道为什么或如何解决这个问题。我怎样才能正确地做到这一点?

【问题讨论】:

  • 您的程序所做的一切对我来说都是段错误。按顺序获取您的代码并编译MCVE
  • 奇怪。它不会在 osx 上出现段错误
  • 分段错误通常是代码中某些未定义结构的标志,而众所周知的未定义行为允许任何事情发生。包括不分段错误。

标签: c algorithm data-structures insertion-sort


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    通常使用哨兵节点而不是 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);
    

    【讨论】:

      猜你喜欢
      • 2014-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-19
      相关资源
      最近更新 更多