C 如何在运行时创建和排序单链表?

C 如何在运行时创建和排序单链表?,c,pointers,linked-list,C,Pointers,Linked List,我试图通过读取文本文件创建一个链表,并以升序输出读取的单词及其计数 除了尝试在运行时对节点进行排序外,一切正常 首先,我尝试了冒泡排序,但我无法理解链表开头部分的逻辑 第二,我一直试着比较x->next的计数,直到我发现一个比我想推回的大。然后我交换它们。我使用了许多指针,但有时可以工作,但在某些边缘情况下失败 我本应该保存一些代码,让人们指出我的逻辑缺陷,但我只是有点沮丧,试图从头开始 有人能提供一些好的逻辑或显式伪逻辑吗?多谢各位 #include<stdio.h> #inclu

我试图通过读取文本文件创建一个链表,并以升序输出读取的单词及其计数

除了尝试在运行时对节点进行排序外,一切正常

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

第二,我一直试着比较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;
    }
}
#包括
#包括
#包括
#包括
#定义最大999
定义表结点
{
字符*名称;
整数计数;
结构节点*下一步;
}节点;
无效插入(节点**,字符*);
void freeNode(节点**);
int main()
{
字符str[MAX];
node*head=NULL;
while(getword(str,MAX))
{
插入(&head,str);
}
打印头;
自由(头);
返回0;
}
空插入(节点**头,字符*str)
{
节点*中间=*头部;
节点*left=NULL,*right=NULL;
中途(中)
{
if(strcmp(mid->name,str)==0)
{
++(中->计数);
节点*温度=左侧;
同时(中间->计数>右侧->计数)
{
//printf(“在%s%s%s\n”中,左->名称,中->名称,右->名称);
左->下一步=中->下一步;
中->下一步=右->下一步;
右->下一步=中间;
左=左->下一步;
如果(mid->next!=NULL)right=mid->next;
如果(左=中)断开;
//printf(“在%s%s%s\n\n”中,左->名称,中->名称,右->名称);
//睡眠(3);
}
返回;
}
左=中;
mid=mid->next;
如果(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;
新建节点->下一步=*头部;
*头=新节点;
}
无效自由节点(节点**头部)
{
节点*温度;
while(*头)
{
温度=(*头部)->下一步;
自由(*头);
(*头)=空;
(*水头)=温度;
}
}

我刚刚处理了几个边缘案例。我确保当第一个节点被重复时,将确保向下移动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;
}

谷歌合并排序。IMHO它是对单连通列表进行排序的最佳算法

从以下节点列表开始:

node3 -> node7 -> node1 -> node20 -> node11 -> node13 -> NULL
长度为1的每个子列表(通常)排序如下:

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

node3 -> node7 -> node20 -> node1 -> 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}
{node1 -> node3 -> node7 ->node20}->{node007 -> node11 -> node13}->NULL 

merge(node1,node007,4):
returns
{node1 -> node3 -> node7 -> node007 -> node11 -> node13 -> ode20}->NULL
因此,您将得到两个长度为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}
{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;
结果=空;
as node1NULL;
n2={node20}->t2;
count2=1;
作为node3node3}->NULL;
n1={node7}->t1;
count1=1;
作为node7node3->node7}->NULL;
n1=t1;
count1=0;(合并完成);
作为计数2!=0:result={node1->node3->node7->node20}->NULL。

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

要交换“当前”节点和“当前的下一个”节点,你还需要跟踪“当前的上一个”节点。要进行(冒泡)排序,请在列表上循环,如果“current”大于“next of current”,则交换这两个节点。执行此操作直到不执行任何交换。@一些程序员朋友我试图使用左中右预电流、当前和当前->下一步,但我尝试执行当前->下一步的条件总是失败并使程序崩溃您的目的不清楚。是否要插入到有序列表中?
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.