当我被告知“排序单链表”时会发生什么

时间:2012-01-22 14:40:03

标签: data-structures linked-list

这可能是为了迂腐而不是家庭作业。我有一个关于'排序单链表'的问题(任何类型的列表)假设这个问题我们想要按每个节点中值的升序排序。

这个问题是否希望我只是通过交换列表中每个节点的值来对列表进行排序,以便值按某种顺序(升序/降序)。这里将更改节点的原始值(排序之前)以反映排序列表。这里返回相同的早期头指针,但现在其中包含最小元素,这可能与其早期元素不同。

就像下面的C代码一样(下面的代码可能不会按原样编译,但我的工作正常。发布在这里作为说明以明确我的观点):

struct lnk_lst 
{
   int val;
   struct lnk_lst *next;
};

main()
{

  //Assume curr is the head node of the singly linked list created with some values
curr = llist_bubble_sort(curr);

}

struct lnk_lst* llist_bubble_sort(struct lnk_lst *lst)
{
    int i,n=0,tmpint;
    struct lnk_lst *tmp=lst,*tmp2=lst;

    while(tmp->next)
    {
        lst = tmp2;
        while(lst->next)
        {
            if(lst->val > lst->next->val)
            {
                tmpint = lst->val;
                lst->val = lst->next->val;
                lst->next->val = tmpint;
            }
            lst = lst->next;
        }
        tmp = tmp->next;
    }

    return tmp2;

}

OR

是否期望将原始排序中具有最小元素(假设升序)的节点的指针移动为新的头节点,然后具有下一个最小元素的节点链接到头节点,因此这样就完全重新排序了列表,现在返回的头节点与之前的指针不同。

如果列表排序的解释是第二次,那么我必须看看如何在代码中完成这个想法。

2 个答案:

答案 0 :(得分:1)

链接列表背后的整个想法是可以在不影响内容的情况下更改链接。更改指针有时需要创建指向指针变量的指针。另外:如果你只交换内容,你也可以省略 - >下一个指针,改用数组,然后交换数组的内容。

恕我直言,自然排序链表的方式是mergesort。下面的片段将列表拆分为两部分:已经存在的节点和不存在的节点。第二个列表已排序,两个列表已合并。拆分和合并都涉及一些指向指针的变量。

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

struct llist {
        struct llist *next;
        char *payload;
        };

int llist_cmp(struct llist *l, struct llist *r);
struct llist * llist_split(struct llist **hnd
                        , int (*cmp)(struct llist *l, struct llist *r) );
struct llist * llist_merge(struct llist *one, struct llist *two
                        , int (*cmp)(struct llist *l, struct llist *r) );
struct llist * llist_sort(struct llist *ptr
                        , int (*cmp)(struct llist *l, struct llist *r) );

struct llist * llist_split(struct llist **hnd, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *this, *save, **tail;

for (save=NULL, tail = &save; this = *hnd; ) {
        if (! this->next) break;
        if ( cmp( this, this->next) <= 0) { hnd = &this->next; continue; }
        *tail = this->next;
        this->next = this->next->next;
        tail = &(*tail)->next;
        *tail = NULL;
        }
return save;
}

struct llist * llist_merge(struct llist *one, struct llist *two, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *result, **tail;

for (result=NULL, tail = &result; one && two; tail = &(*tail)->next ) {
        if (cmp(one,two) <=0) { *tail = one; one=one->next; }
        else { *tail = two; two=two->next; }
        }
*tail = one ? one: two;
return result;
}

struct llist * llist_sort(struct llist *ptr, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *save;

  save=llist_split(&ptr, cmp);
  if (!save) return ptr;

  save = llist_sort(save, cmp);

  return llist_merge(ptr, save, cmp);
}

int llist_cmp(struct llist *l, struct llist *r)
  {
  if (!l) return 1;
  if (!r) return -1;
  return strcmp(l->payload,r->payload);
  }


struct llist lists[] =
{{ lists+1, "one" }
,{ lists+2, "two" }
,{ lists+3, "three" }
,{ lists+4, "four" }
,{ lists+5, "five" }
,{ lists+6, "six" }
,{ lists+7, "seven" }
,{ lists+8, "eight" }
,{ NULL, "nine" }
        };

int main()
{
struct llist *root,*tmp;

root = lists;

fprintf(stdout, "## %s\n", "initial:" );
for (tmp=root; tmp; tmp=tmp->next) {
        fprintf(stdout, "%s\n", tmp->payload);
        }

fprintf(stdout, "## %s\n", "sorting..." );
root = llist_sort(root, llist_cmp);

for (tmp=root; tmp; tmp=tmp->next) {
        fprintf(stdout, "%s\n", tmp->payload);
        }
fprintf(stdout, "## %s\n", "done." );

return 0;
}

结果:

## initial:
one
two
three
four
five
six
seven
eight
nine
## sorting...
eight
five
four
nine
one
seven
six
three
two
## done.

答案 1 :(得分:0)

排序链表的正确方法是第二种。这也是有道理的,因为通常您希望在保留其他属性值的同时对某些属性上的对象进行排序。在这种情况下,第一种方法没有多大帮助。

这个想法类似于传统的排序方法。例如,您可以通过迭代元素然后将正确排序的链接列表中的右侧位置中的下一个元素插入到该元素来使用插入排序。有关C中的详细代码,您可以看到Wikipedia页面here