简体   繁体   English

在C中的链表上插入排序?

[英]Insertion sort on linked list in C?

I've tried searching for a problem similar to mine, but haven't found much help. 我试过寻找类似于我的问题,但没有找到太多帮助。

I have a linked list of structs of this type: 我有一个这种结构的链表:

struct PCB {
    struct PCB *next;
    int reg1, reg2;
};

I first create 10 PCB structs linked together in this way: 我首先以这种方式创建10个PCB结构:

for(i=20;i<=30;i++) {
        curr = (struct PCB *)malloc(sizeof(struct PCB));
        curr->reg1 = i;
        curr->next  = head;
        head = curr;
    }

I then need to create 20 more PCB structs, but their reg1 values need to be generated using rand() . 然后我需要再创建20个PCB结构,但是需要使用rand()生成它们的reg1值。 I'm currently doing that as so: 我正在这样做:

for (j = 0;j<20;j++) {
        curr = (struct PCB *)malloc(sizeof(struct PCB));
        curr->reg1 = rand()%100;
        curr->next  = head;
        head = curr;
    }

However, when inserting these PCB structs into the linked list with random reg1 values, I need to be inserting them in the linked list in order (insertion sort). 但是,当使用随机reg1值将这些PCB结构插入到链表中时,我需要按顺序将它们插入到链表中(插入排序)。 What is the best way to approach this in just a single-link linked list? 在单链接链表中处理此问题的最佳方法是什么? Thanks 谢谢

EDIT: I am now keeping track of the first created struct to be able to loop through the linked list from the beginning: 编辑:我现在正在跟踪第一个创建的结构,以便能够从头开始循环链接列表:

// create root struct to keep track of beginning of linked list
root = (struct PCB *)malloc(sizeof(struct PCB));
root->next = 0;  
root->reg1 = 20;

head = NULL;

// create first 10 structs with reg1 ranging from 20 to 30
for(i=21;i<=30;i++) {
    curr = (struct PCB *)malloc(sizeof(struct PCB));
    // link root to current struct if not yet linked
    if(root->next == 0){
        root->next = curr;
    }
    curr->reg1 = i;
    curr->next  = head;
    head = curr;
}

Then, when I'm creating the additional 10 PCB structs that need to be insertion sorted: 然后,当我创建需要插入排序的额外10个PCB结构时:

// create 20 more structs with random number as reg1 value
    for (j = 0;j<20;j++) {
        curr = (struct PCB *)malloc(sizeof(struct PCB));
        curr->reg1 = rand()%100;
        // get root for looping through whole linked list
        curr_two = root;
        while(curr_two) {
            original_next = curr_two->next;
            // check values against curr->reg1 to know where to insert
            if(curr_two->next->reg1 >= curr->reg1) {
                // make curr's 'next' value curr_two's original 'next' value
                curr->next = curr_two->next;
                // change current item's 'next' value to curr
                curr_two->next = curr;
            }
            else if(!curr_two->next) {
                curr->next = NULL;
                curr_two->next = curr;
            }
            // move to next struct in linked list
            curr_two = original_next;
        }
        head = curr;
    }

But this immediately crashed my program. 但这立刻导致了我的计划崩溃。

The "best" way would probably be to implement a new function for the insertion. “最佳”方式可能是实现插入的新功能。 This function would iterate over the list until it finds a node whose next nodes value is less or equal to the node you want to insert, then put the new node before the next node. 此函数将遍历列表,直到找到next节点值小于或等于要插入的节点的节点,然后将新节点放在next节点之前。


How about this function: 这个功能怎么样:

void insert(struct PCB **head, const int reg1, const int reg2)
{
    struct PCB *node = malloc(sizeof(struct PCB));
    node->reg1 = reg1;
    node->reg2 = reg2;
    node->next = NULL;

    if (*head == NULL)
    {
        /* Special case, list is empty */
        *head = node;
    }
    else if (reg1 < (*head)->reg1)
    {
        /* Special case, new node is less than the current head */
        node->next = *head;
        *head = node;
    }
    else
    {
        struct PCB *current = *head;

        /* Find the insertion point */
        while (current->next != NULL && reg1 < current->next->reg1)
            current = current->next;

        /* Insert after `current` */
        node->next = current->next;
        current->next = node;
    }
}

You would call it like this: 你会这样称呼它:

insert(&root, rand() % 100, 0);

Here is the simplified version of @Joachim: 这是@Joachim的简化版本:

void insert(struct PCB **head, const int reg1, const int reg2)
{
    struct PCB *new ;
        /* Find the insertion point */
    for (       ;*head; head = & (*head)->next)
    {
        if ((*head)->reg1 > reg1) break;
    }

    new = malloc(sizeof *new );
    new->reg1 = reg1;
    new->reg2 = reg2;
    new->next = *head;
   *head = new;
}

The idea is simple: there need not be any special cases , in any case: a pointer needs to be changed, this could be the root pointer, or the tail pointer, or some pointer in the midddle of the LL. 这个想法很简单:在任何情况下都不需要任何特殊情况:需要更改指针,这可能是根指针,尾指针,或LL中间的一些指针。 In any/every case: 在任何/每种情况下:

  • the new node actually steals this pointer: 新节点实际上窃取了这个指针:
  • it makes it point at itself 它使它指向自己
  • it adopts the previous value as a successor (assigns it to its ->next pointer. 采用前一个值作为后继(将其赋值给->next指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM