【问题标题】:How do I sort a linked list in a alphabetical order in c如何在c中按字母顺序对链表进行排序
【发布时间】:2016-10-12 02:00:23
【问题描述】:

我正在尝试按字母顺序对链接列表进行排序,但我的排序算法似乎没有。如何对列表进行排序?

typedef struct  s_file
{
    char        *file_name;
    struct      s_file *next;
}               t_file;

void    sort_alpha(t_file **begin_list)
{
    t_file  *list;
    char    *tmp;

    list = *begin_list;
    if (list)
    {
        while (list)
        {
            if (strcmp(list->file_name, list->next->file_name) < 0)
            {
                tmp = list->file_name;
                list->file_name = list->next->file_name;
                list->next->file_name = tmp;
            }
            list = list->next;
        }
    }
}

【问题讨论】:

  • 您需要将每个元素与每个其他元素进行比较,以找到它在排序列表中的位置。 (是的,有更好的算法不需要 O(n^2 ) 比较)。阅读冒泡排序或选择排序。
  • 从你的列表中创建一个指针数组,然后在数组上调用qsort,然后按排序顺序重新填充你的列表几乎更容易(对于任何事情来说,速度都快得多,但微不足道小清单)
  • 代码所做的只是将最大的名称移动到列表中的最后一个节点。代码需要一个外循环来重复这个过程,直到没有节点被检测到是乱序的。从技术上讲,这不是对列表进行排序,而是对列表中节点中的名称进行排序,而不是对节点(结构)进行排序。一种替代方法是从一个空列表开始,然后从原始列表中删除节点并按顺序将它们“插入”到最初为空的列表中,当原始列表被清空时产生一个排序列表。
  • @SilentMonk 提出的“阿尔法排序”算法总是bubble sort快,总是比selection sort.快很多它的最佳时间复杂度比 O(n) 好,最坏的情况总是小于 O(n^2)。选择排序复杂度始终为 O(n^2)。请参阅:Time complexity chart@DavidC.Ranking 当然qsort 平均比bubble sort 快得多。 @rcgldr 有了完整的算法,就不需要外循环了。

标签: c sorting


【解决方案1】:

再次查看代码后,我对其进行了优化,以符合@TenTen Peter 的初衷。不需要外循环。排序正确:

#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>

// definition of the structure (global scope)
typedef struct  s_file
{
    char        *file_name;
    struct      s_file *next;
} t_file;

int static counter = 0;

void sort_alpha(t_file **begin_list)
{
  t_file    *list;
  char  *tmp;
  list = *begin_list;
  if (list)
    {
        while (list && list->next)
        {
            if (strcmp(list->file_name, list->next->file_name) > 0)
            {
                tmp = list->file_name;
                list->file_name = list->next->file_name;
                list->next->file_name = tmp;
                counter = counter + 1;
                printf("swap=%d\n",counter);
            }
        list = list->next;
        }
    }
}

int list_size(t_file **alst)
{
    int size = 0;
    t_file  *conductor;  // This will point to each node as it traverses the list
    conductor = *alst;      
    if ( conductor != 0 ) 
    {
        size = 1;
        while ( conductor->next != 0)
        {
            conductor = conductor->next;
            size = size + 1;
        }
     }
    return size;
}

void list_add(t_file **alst, t_file *newElement)
{
    printf("list_add->");
    if (newElement)
    {
         newElement->next = *alst;
         *alst = newElement;

        // Printing the added element
        printf("list_add:newElement=%s\n",(*alst)->file_name);

        // sorting:
        sort_alpha(alst); 
    }
    else
    {
        printf("NULL entry\n");
    }
}

t_file  *newEntry(char *file_name)
{
    t_file *file;
    file = (t_file *) malloc( sizeof(t_file) );
    printf("newEntry:file_name= %s\n",file_name);
    if (file)
    {
       file->file_name = file_name;
       file->next = NULL;
   }
   return (file);
}

// Untested
void read_dir(char *dir_name, t_file **begin_list)
{
    DIR *dir;   
    struct dirent *entry;
    dir = opendir(dir_name);
    if (!dir)
   {
        perror(dir_name);
        return;
   }
    while ((entry = readdir(dir)) != NULL){
        list_add(begin_list, newEntry(entry->d_name));
   }    
    closedir(dir);
}

int main(int ac, char **av)
{
    t_file *s,*iter,*e2,*e3,*e4,*e5,*e6,*e7;
    int j=0;
    
    printf("*Program Start*\n");        

    // Creating entries:
    s  = newEntry("dHea");
    e2 = newEntry("bbcx");
    e3 = newEntry("abcd");
    e4 = newEntry("cbcd");
    e5 = newEntry("cbad");
    e6 = newEntry("bbcd");
    e7 = newEntry("cbaa");

    // Adding entries to the list and sorting at the same time
    list_add(&s, e2);
    list_add(&s, e3);
    list_add(&s, e4);
    list_add(&s, e5);
    list_add(&s, e6);
    list_add(&s, e7);
    
    // It was done by:
    // read_dir(av[1], &s); // Untested
    
    // Print the sorted list
    iter = s;
    while (iter)
    {
        j++;
        printf("Printing sorted list: element %d = %s\n",j,iter->file_name);
        iter = iter->next;
    }

    printf("*Program End**\n");
    return 0;
}

输出:

*Program Start*
newEntry:file_name= dHea
newEntry:file_name= bbcx
newEntry:file_name= abcd
newEntry:file_name= cbcd
newEntry:file_name= cbad
newEntry:file_name= bbcd
newEntry:file_name= cbaa
list_add->list_add:newElement=bbcx
list_add->list_add:newElement=abcd
list_add->list_add:newElement=cbcd
swap=1
swap=2
list_add->list_add:newElement=cbad
swap=3
swap=4
list_add->list_add:newElement=bbcd
swap=5
list_add->list_add:newElement=cbaa
swap=6
swap=7
swap=8
Printing sorted list: element 1 = abcd
Printing sorted list: element 2 = bbcd
Printing sorted list: element 3 = bbcx
Printing sorted list: element 4 = cbaa
Printing sorted list: element 5 = cbad
Printing sorted list: element 6 = cbcd
Printing sorted list: element 7 = dHea
*Program End**

代码在这里:code

编辑:由于有人可能担心上述算法的效率,我添加了一个交换计数器。它计算需要交换指针的次数发生了多少次。 (请注意,不涉及复制)。 对于上述数据,该算法似乎非常有效。我们的 7 个元素列表只有 8 个交换!

为了比较这些是各种排序算法的排序时间:

冒泡排序[最佳:O(n),最差:O(N^2)]

选择排序[最佳/最差:O(N^2)]

插入排序[最佳:O(N),最差:O(N^2)]

快速排序[最佳:O(N lg N),平均:O(N lg N),最差:O(N^2)]

堆排序[最佳/平均/最差:O(N lg N)]

计数排序[最佳/平均/最差:O(N)]

基数排序 [最佳/平均/最差:O(N)]

来源维基Sorting

让我们将上述算法与经典冒泡排序算法针对同一组数据进行比较。 这是测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int count = 0; 

int main(void) {

    char name[10][8], tname[10][8], temp[8];
    int i, j, n;

    printf("Enter the number of names\n");
    scanf("%d", &n);
    printf("Enter %d names\n", n);

    // reading names
    for (i = 0; i < n; i++)
    {
        scanf("%s", name[i]);
        strcpy(tname[i], name[i]);
    }

    // standard bubble sort  
    for (i = 0; i < n - 1 ; i++)
    {
        for (j = i + 1; j < n; j++)
        {
            if (strcmp(name[i], name[j]) > 0)
            {
                strcpy(temp, name[i]);
                strcpy(name[i], name[j]);
                strcpy(name[j], temp);

                count = count + 1;
                printf("swap %d ", count);
            }
        }
    }

    // Print results:
    printf("\n----------------------------------------\n");
    printf("Input Names \tSorted names\n");
    printf("------------------------------------------\n");
    for (i = 0; i < n; i++)
    {
        printf("%s\t\t\t%s\n", tname[i], name[i]);
    }
    printf("------------------------------------------\n"); 
    return 0;
}

输入:

7 dHea bbcx abcd cbcd cbad bbcd cbaa

结果:

Enter the number of names
Enter 7 names
swap 1 swap 2 swap 3 swap 4 swap 5 swap 6 swap 7 swap 8 swap 9 swap 10 swap 11 swap 12 swap 13 
----------------------------------------
Input Names     Sorted names
------------------------------------------
dHea            abcd
bbcx            bbcd
abcd            bbcx
cbcd            cbaa
cbad            cbad
bbcd            cbcd
cbaa            dHea

reference

因此,对于同一组数据,我们在冒泡排序算法中需要 13 次交换,而不是 alpha 算法中的 8 次。

(这种特殊的冒泡排序使用strcpy 函数而不是交换指针。)

我的结论是,提出的“阿尔法排序”算法将总是比经典冒泡排序更有效。这是因为我们立即开始排序,将元素连续添加到排序列表中。基本上我们可以将此算法视为改进的冒泡排序。

值得注意的是,不断增长的列表始终是排序的,这对于某些类型的应用程序非常有用。

【讨论】:

  • 很难想象为什么,如果您从list_add 调用排序,您不会简单地按排序顺序添加节点。它只需要迭代,直到你找到新节点之前的节点并将其插入那里(例如插入cbcd,迭代a,b,c,cb,cba,[insert here]。在开头插入节点,然后为每次插入调用完整列表排序,变得更多随着列表大小的增加,效率会降低。如果您从list_add 排序,最好只按排序顺序插入节点。
  • @DavidC.Rankin 这不是“完全排序”。我们不复制元素,而只是交换指针。您能否发布您对void list_add(t_file **alst, t_file *newElement);void sort_alpha(t_file **begin_list); 的建议,以便我们比较效率?我很好奇它是否可以降低成本并且仍然有效。
  • 好吧,我知道代码的作用,我的意思是你将 every 指针交换到排序顺序插入点,而你可以简单地在插入处插入观点。另一种方法是完全从list_add 中取出sort_alpha,并在读取所有数据后调用它一次。正如所写,您不必要地乱序插入一个节点作为开始节点,然后将每个指针交换到添加的节点应该适合的位置——对于添加的每个节点。我并不是说你的代码不起作用,我只是说很难编写一种效率较低的方法。
  • @sg7 感谢您的帮助,它可以工作,但很难对混合大小写进行排序。
  • @TenTenPeter 我想你可能对此感兴趣:stackoverflow.com/questions/12646734/…
猜你喜欢
  • 2015-12-08
  • 2019-05-14
  • 2014-06-04
  • 2021-12-07
  • 2013-05-02
  • 2014-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多