【问题标题】:How to create and sort a singly linked list in runtime?如何在运行时创建和排序单链表?
【发布时间】:2018-04-29 09:04:05
【问题描述】:

我正在尝试通过读取文本文件创建一个链接列表,并按升序输出读取的单词及其计数。

除了尝试在运行时对节点进行排序之外,一切都很好。

首先我尝试了冒泡排序,但我无法理解链表开头部分的逻辑。

其次,我一直在比较 x->next 的计数,直到找到一个比我想推回的更大的计数。然后我交换它们。我使用了很多指针,但有时它可以工作,但在某些边缘情况下会失败。

我应该保存一些代码,让人们指出我的逻辑缺陷,但我有点沮丧,只是想从头开始。

有人可以提供一些好的逻辑或明确的伪吗?非常感谢

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#define MAX 999
typedef struct Node
{
    char *name;
    int count;
    struct Node *next;
}node;
void insert(node **,char *);
void freeNode(node **);
int main()
{
    char str[MAX];
    node *head = NULL;
    while(getword(str,MAX))
    {
        insert(&head,str);
    }
    print(head);
    free(head);
    return 0;
}
void insert(node **head,char *str)
{
     node *mid = *head;
node *left = NULL, *right = NULL;
while(mid)
{
    if(strcmp(mid->name,str) == 0)
    {
        ++(mid->count);
        node *temp = left;

        while(mid->count > right->count)
        {
            //printf("in %s %s %s\n",left->name,mid->name, right->name);
            left->next = mid->next;
            mid->next = right->next;
            right->next = mid;

            left = left->next;
            if(mid->next != NULL) right = mid->next;
            if(left == mid) break;
            //printf("in %s %s %s\n\n",left->name,mid->name, right->name);
           // sleep(3);
        }

        return;
    }
    left = mid;
    mid = mid->next;
    if(mid != NULL) right = mid->next;
}

    node *newnode = (node *) malloc(sizeof(node));
    newnode->name = (char *) malloc(MAX * sizeof(char));
    strcpy(newnode->name,str);
    newnode->count = 1;
    newnode->next = *head;
    *head = newnode;
}
void freeNodes(node **head)
{
    node *temp;
    while(*head)
    {
        temp = (*head)->next;
        free(*head);
        (*head) = NULL;
        (*head) = temp;
    }
}

【问题讨论】:

  • 要交换“当前”节点和“当前的下一个”节点,您还需要跟踪“当前的上一个”节点。要(冒泡)排序,遍历列表,如果“当前”大于“当前的下一个”,则交换这两个节点。执行此操作,直到不执行任何交换。
  • @ 一些程序员老兄我试图使用左中右 precurret、current 和 current->next,但我尝试执行 current->next 的条件总是失败并导致程序崩溃
  • 你的目的不明确。是否要插入到 有序 列表中?

标签: c pointers linked-list


【解决方案1】:

我刚刚处理了一些边缘案例。我确保当第一个节点重复时将确保向下移动一个

node *mid = *head;
node *left = NULL, *right = NULL;
while(mid)
{
    if(strcmp(mid->name,str) == 0)
    {
        ++(mid->count);
        if(mid->next == NULL) return;
        node *temp = left;
        if(left == NULL)
        {
            left = mid->next;
            mid->next = left->next;
            left->next = mid;
            *head = left;
            right = mid->next;

        }
            while(mid->count > right->count)
            {
                left->next = mid->next;
                mid->next = right->next;
                right->next = mid;

                left = left->next;
                if(mid->next != NULL) right = mid->next;
                if(left == mid) break;
                //printf("in %s %s %s\n\n",left->name,mid->name, right->name);
               // sleep(3);
            }

        return;
    }
    left = mid;
    mid = mid->next;
    if(mid != NULL) right = mid->next;
}

【讨论】:

    【解决方案2】:

    谷歌合并排序。恕我直言,这是对单连接列表进行排序的最佳算法。

    从列表节点开始:

    node3 -> node7 -> node1 -> node20 -> node11 -> node13 -> NULL
    

    每个长度为 1 的子列表都(简单地)排序:

    { node3 } is sorted
    { node7 } is sorted
    

    然后将两个连续的长度为1的子列表合并成长度为2的子列表:

    node3 -> node7 -> node20 -> node1 -> node11 -> node13 -> node007 -> NULL
    

    进入

    {node3 -> node7}->{node1 -> node20}->{node11 -> node13}->{node007} -> NULL
    

    node007 被认为等于node7

    然后将两个连续的长度为2的子列表合并成长度为4的子列表:

    {node3 -> node7}->{node1 -> node20}->{node11 -> node13}->{node007} -> NULL
    
    merge(node3, node1, 2):
    returns {node1 -> node3 -> node7 ->node20}
    
    merge(node11, node007, 2):
    returns {node007 -> node11 -> node13}
    

    所以你得到两个长度为 4 的排序子列表:

    {node1 -> node3 -> node7 ->node20}->{node007 -> node11 -> node13}->NULL 
    
    merge(node1,node007,4):
    returns
    {node1 -> node3 -> node7 -> node007 -> node11 -> node13 -> ode20}->NULL
    

    所以长度总是加倍,当它等于或大于整个列表的长度时你就完成了。

    合并总是比较每个列表的第一个元素并从列表中弹出较小的元素并将其附加到结果尾部:

    merge(n1 = {node3 -> node7}->t1 , n2 = {node1 -> node20}-> t2 , 2):
    

    count1 = count2 = 2;
    result = NULL;
    as node1 < node3  : result = { node1 }-> NULL;
                        n2 = { node20 } -> t2;
                        count2 = 1;
    as node3 < node20 : result = {node1 -> node3}-> NULL;
                        n1 = {node7}->t1;
                        count1 = 1;
    as node7 < node20 : result = {node1 -> node3-> node7 }-> NULL;
                        n1 = t1;
                        count1 = 0; (merge finished);
    as count2 != 0 :    result = {node1 -> node3-> node7 -> node20 } -> NULL.
    

    这是应该给你一个想法的所有伪代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-13
      • 1970-01-01
      • 2020-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-03
      相关资源
      最近更新 更多