基本排序(四):索引指针排序、链表排序、关键字排序

1. 索引和指针排序

  • 因为元素的数量或者数据量巨大等原因,我们不希望频繁移动要排序的元素。因此,不移动元素的排序方法是维持一个索引数组或者索引指针,而排序的目标就是重排索引数组或指针。

    如: 初始化for(int i = 0; i < N; i++) a[i] = &data[i];

    使用间接比较#define less(A, B) (*A < *B)

  • 使用下标或指针排序的主要原因是避免扰乱要排序的数据。我们可以对只读文件进行排序,或者针对一个文件的多个关键字进行排序。

    另一个原因是避免了移动整个记录,对大型记录(相对小的关键字值)的移动开销是巨大的。

    例如:struct record { char [30]name; int num;}

    int less(Item a, Item b)
    {   return a->num < b->num;     }

    任意sort实现都将会基于这种类型的在整型域关键字上进行指针排序;

    int less(Item a, Item b)
    {    return strcmp(a->name, b->name) < 0;   }

    任意sort实现都将会基于这种类型的在字符串域关键字上进行指针排序;

  • 间接排序要求额外的空间存储下标或指针数组,以及额外的空间进行间接比较,但是相比不需要移动数据的灵活性,这些开销不算大。对于大型记录的文件,我们一般选择间接排序

2. 链表排序

应用范围和基本原理

  • 对于存储在链表中的数据,我们需要使用链表排序方式。在某些情况下,只有数据能够按照高效支持链表操作的顺序方式时,算法才会有用。
  • 通常我们所操作的表节点的指针时有应用系统的其他部分维护的(多重链表),这意味着排序程序只能改变节点中的链接,不能改变关键字值和其他信息.我们需要的是改变链接本身,以使经过链接遍历链表时,节点时按顺序出现的,同时经由其他链接访问时,不影响他们原本的顺序

算法实现

我们维持一个输入链表(h->next指向这个链表,有表头),一个输出链表(out指向这个链表)。当链表非空时,遍历链表找出最大元素(因为链表之前易于插入元素,先插大的,在大的之前依次插入小的),然后从输入表中去除这个最大元素,把他插入到输出表的前面。其中,找出最大元素函数findMax(),返回的是最大元素节点的上一节点的地址。(因为要想删除一个节点,必须知道它前一节点的地址prev->next = prev->next->next;)

C程序实现

link linklist_sort(link h)
{
    link out, t, max;
    out = NULL, t = NULL, max = NULL;
    while(h->next != NULL)
    {
        max = findMax(h);
        t = max->next;//最大元素节点
        max->next = max->next->next;//删除max节点
        t->next = out;//将t插入到out前
        out = t;//返回out
    }
    h->next = out;
    return h;
}

在一些表的处理中,我们不需要详细实现排序过程,只需要像插入排序依次向表中插入新元素,使表有序。

3. 关键字索引排序

原理

所谓排序,就是要整理文件中的记录,使之按关键字递增(或递减)次序排列起来。

被排序的对象–文件由一组记录组成。记录则由若干个数据项(或域)组成。其中有一项可用来标识一个记录,称为关键字项。该数据项的值称为关键字(Key)。

在待排序的文件中,若存在多个关键字相同的记录,我们希望通过按关键字索引排序,其中关键字是在一个小范围内的整数。

例如:

1)我们统计不同值的关键字个数分别是多少:6个0,4个1,2个2,3个3.

2)局部统计比其他关键字小的关键字的个数:0个关键字比0小,6个关键字比1小,10个关键字比2小,12个关键字比3小。

3)根据上述统计数作为索引将关键字放到合适位置:在开头0开始放具有0关键字的元素0,根据0,增加指针值,放下一个0关键字的元素3……);将具有3关键字的元素从位置12开始放起(12个比3小);以此类推

C程序实现

void keyword_sort(Item a[], int l, int r)
{
    Item b[r-l+1];
    int cnt[M];//M为关键字的个数
    for(int j = 0; j < M; j++)//初始化个数全0
        cnt[j] = 0;
    for(int i = l; i <= r; i++) //统计不同值的关键字个数,
        cnt[a[i]+1]++;
    for(int j = 1; j < M; j++)//统计比关键字j小的关键字的个数,cnt[j]存储比关键字j小的元素个数
        cnt[j] = cnt[j] + cnt[j-1];
    for(int i = l; i <= r; i++) //按关键字个数索引放到辅助数组b中
        b[cnt[ a[i] ]++] = a[i];
    for(int i = l; i <= r; i++)
        a[i] = b[i-l];
}

如果要排序的文件很大,使用辅助数组b会导致内存分配问题,可以通过使用原位排序避免使用额外数组完成。

参考资料

《算法:C语言实现》P180~190

时间: 2024-11-11 05:38:48

基本排序(四):索引指针排序、链表排序、关键字排序的相关文章

常见的五类排序算法图解和实现(多关键字排序:基数排序以及各个排序算法的总结)

基数排序思想 完全不同于以前的排序算法,可以说,基数排序也叫做多关键字排序,基数排序是一种借助“多关键字排序”的思想来实现“单关键字排序”的内部排序算法. 两种方式: 1.最高位优先,先按照最高位排成若干子序列,再对子序列按照次高位排序 2.最低位优先:不必分子序列,每次排序全体元素都参与,不比较,而是通过分配+收集的方式. 多关键字排序 例:将下表所示的学生成绩单按数学成绩的等级由高到低排序,数学成绩相同的学生再按英语成绩的高低等级排序.        第一个关键字是数学成绩,第二个关键字是英

动画 | 大学四年结束之前必须透彻的排序算法

目录 如何分析一个"排序算法"? 开始分析冒泡"排序算法" 开始分析"插入排序算法" 开始分析"选择排序算法" 开始分析"希尔排序算法" 开始分析"快速排序算法" 开始分析"并归排序算法" 开始分析"基数排序算法" 开始分析"堆排序算法" 为什么插入排序要比冒泡排序更受欢迎? 现如今大学生学习排序算法,除了学习它的算法原理.代码

链表的基本排序

选择排序:链表的选择排序和一般的选择排序基本思路上是一样的,只是对于链表而言,他的指针不一样 遍历链表,每次找出一个最小的节点,将其值与未排序节点的首个节点交换,这里需要一个指针标记值最小的节点. Node *SelectSort( Node *L ){ Node *p, *q, *small; int temp; for( p = L->next; p->next != NULL; p = p->next )    /*每次循环都找出一个最小值,将最小值交换到第一位,然后将指针向后移动

【C语言】【数据结构】菜鸟学习日志(四) 用二叉树实现非递归排序

唉,由于要备战考研,这篇博文可能是我这一年最后一次更新啦! 其实断断续续的也没有写很多,而且大多都是很初级.很简单的东西,没有和大家分享什么高阶的东西.这也正应了我们<菜鸟学习日志>的标题嘛! 不过说回来我还是很喜欢写博文的.一方面总结学到的知识,以后也可以自己看看别做了就忘了:另一方面,写博文也让我在学习的过程中更加认真,以免分享了错误的知识. 写的东西好不好呢是一说,好像有一些点击量,不过看的人估计也不多.只是我还算乐在其中吧! 大学生活说到底过得有点浪了,导致我苦逼地走向了考研的不归路-

揭开链表逆转和排序的面纱

我们都知道,对于顺序表逆转和排序就如同数组一样,将数据改变位置就行,因为他们的数据是连续的空间存储的,但是对于链表如果你也这样只改变值进行排序,那你就太不懂链表的心了,链表的特点就是动态开辟游离的空间然后依据上一个节点所存的地址来寻找下一个节点,这样使得位置这个概念在链表里显得太不重要,所以对于链表我们如果想要逆转或者排序就是要改变每个节点里面存储的地址,通俗一点就是要改变指针的指向,于是我找到了一种将所有链表逆转和排序的统一算法: (这里所说链表全是带有头节点链表) 简述算法步骤:1.将链表的

下载Lucene4.X实战类baidu搜索的大型文档海量搜索系统(分词、过滤、排序、索引)

Lucene是一个高性能.可伸缩的信息搜索(IR)库.目前最新版本是4.3.1. 它可以为你的应用程序添加索引和搜索能力.Lucene是用java实现的.成熟的开源项目,是著名的Apache Jakarta大家庭的一员,并且基于Apache软件许可 [ASF, License].同样,Lucene是当前非常流行的.免费的Java信息搜索(IR)库. Lucene4.X实战类baidu搜索的大型文档海量搜索系统(分词.过滤.排序.索引),刚刚入手,转一注册文件,视频的确不错,可以先下载看看:htt

对mysql联合索引中的字段进行合理排序

在MySQL的where条件中,有时会用到很多的条件,通常为了加快速度会把这些字段放到联合索引中,可以更快的提高搜索速度: 但是对联合索引中字段顺序的合理排序,便更能提高速度 例子:select * from table where (groupid=1000) and (userid=500) and (time=140012345) 建立的索引也通常很随性的就按照where条件中字段的顺序建立 ALTER  TABLE  table  ADD  INDEX g_u_time_index(gr

MYSQL order by排序与索引关系总结

MySQL InnoDB B-Tree索引使用Tips 这里主要讨论一下InnoDB B-Tree索引的使用,不提设计,只管使用.B-Tree索引主要作用于WHERE和ORDER BY子句.这里讨论的均在MySQL-Server-5.1.42测试 CREATE TABLE `friends` ( `ID` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, `uid`bigint(20) UNSIGNED NOT NULL DEFAULT '0', `fuid`

ztree使用系列四(ztree实现同级拖拽排序并将排序结果保存数据库)

ztree这个系列的最后一篇,也是ztree功能强大的体现之一--排序功能.ztree可以实现所有节点之间随意的拖拽排序功能,我这里根据需要实现了只允许同级之间随意拖拽排序,其实原理都一样,只是范围缩小了一些,多了一些判断而已.下面是每一层的代码,还是采取只贴出功能代码,因为这个拖拽排序功能我感觉很不错,所以单独拿出一篇博客来展示,也方便理解. Jsp页面实现功能的js代码如下: //拖拽前执行 var dragId; function beforeDrag(treeId, treeNodes)