`
hm4123660
  • 浏览: 285408 次
  • 性别: Icon_minigender_1
  • 来自: 广州
博客专栏
Dea4ce76-f328-3ab2-b24a-fb268e1eeb75
数据结构
浏览量:70722
社区版块
存档分类
最新评论

排序算法--归并排序和基数排序

阅读更多

        前面几篇博客学习介绍了插入排序,交换排序,选择排序等排序算法。本篇博客将主要学习介绍归并排序和基数排序。学习完这两个算法,我们的排序算法就学完了。

 

1.归并排序

        归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

 

基本思路

         归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。最简单的归并是直接将两个有序的子表合并称为一个有序表,即二路归并。

 

表的合并

          这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。

实现代码

//两个有序表的合并
void combine(int a[],int lena,int b[],int lenb)
{
	int *c=new int[lena+lenb];//合并表

	int ai=0,bi=0,ci=0;//各个数组下标,初始为0
	
	//a,b数组第一个值对比,取小值放到c中
	while(ai<lena&&bi<lenb)
	{
		if(a[ai]>b[bi])
		{
			c[ci]=b[bi];
			bi++;
			ci++;
		}
		else
		{
			c[ci]=a[ai];
			ai++;
			ci++;
		}
	}

	//若a数组还剩元素,直接放到c数组里
    while(ai<lena)
	{
		c[ci]=a[ai];
		ai++;
		ci++;
	}

	//若b数组还剩元素,直接放到c数组里
	while(bi<lenb)
	{
		c[ci]=b[bi];
		bi++;
		ci++;
	}

	//输出结果
	for(int i=0;i<lena+lenb;i++)
		cout<<c[i]<<" ";
}

 

可以看出来,有序表的整合还是比较容易的,而且效率挺高的,可以达到O(n)。

 

          我们可以利用这个把一个无序表分为两组A,B,再把A,B各自又分为两组,以此类推,直到最后分出来的每组只剩下一个元素,此时子表是有序的(只有一个元素)。然后在两两合并,即最初无序表的有序表。

 

示例图:



 

实现代码

//合并有序数列a[first...mid]和a[mid+1...last], a[first...mid]和a[mid+1...last]一定为有序
void Combine(int a[], int first, int mid, int last)  
{  
	int *temp=new int[last-first+1];//临时记录数组

    int i = first, j = mid + 1;  
    int m = mid,   n = last;  
    int k = 0;  

     //两两对比
    while (i <= m && j <= n)  
    {  
        if (a[i] <= a[j])  
            temp[k++] = a[i++];  
        else  
            temp[k++] = a[j++];  
    }  
      
	//将剩下的记录放到temp中
    while (i <= m)  
        temp[k++] = a[i++];  
      
    while (j <= n)  
        temp[k++] = a[j++];  
      
	//将temp复制回a
    for (i = 0; i < k; i++)  
        a[first + i] = temp[i];  

	delete [] temp;//释放temp内存
}  

void mergesort(int a[], int first, int last)  
{  
    if (first < last)  
    {  
        int mid = (first + last) / 2;  
        mergesort(a, first, mid);    //左边有序  
        mergesort(a, mid + 1, last); //右边有序  
        Combine(a, first, mid, last); //再将二个有序数列合并  
    }  
}  

 

效率分析

        归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是 一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在 O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。

        归并排序过程中,每一趟都需要有一个辅助空间来存储两个子序列表归并的结果,在该排序完毕后释放,所以总的辅助空间复杂度为O(n),显然他不是就地排序。归并排序是一个稳定排序。

 

 

 

2.基数排序

 

基本思想

      基数排序(以整形为例),将整形10进制按每位拆分,然后从低位到高位依次比较各个位。主要分为两个过程:
(1)分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中(比如53,个位为3,则放入3号桶中)
(2)收集,再将放置在0~9号桶中的数据按顺序放到数组中
重复(1)(2)过程,从个位到最高位
例如:
把数组a[10]={75,23,98,44,57,12,29,64,38,82}升序排列,


 

 最终排序结果为12 23 29 38 44 57 64 75 82 98
明白了上面原理,代码实现就简单了,这里我们实现就不用链表了,定义桶的结构为:
#define MAXSIZE 10 //桶里最大放多少值
//桶的结构
struct node
{
	int key[MAXSIZE];//桶里的数据
	int count;//桶里数据的个数
	node()
	{
		count=0;//count为0表示桶内没数字
	}
};
 
定义一个获取各个位上数字的函数
//各个位的值获取
int GetNumInPos(int num,int pos)  
{  
    int temp = 1;  
    for (int i = 0; i < pos - 1; i++)  
        temp *= 10;  
  
    return (num / temp) % 10;  
}  
 
基数排序实现代码
//基数排序
void RadixSort(int a[],int len)
{
	//获取a数组的最大值来确定装几次桶
	int max=0;	
	for(int i=0;i<len;i++)
	{
		if(a[i]>max)
		  max=a[i];
	}
	//计算装桶次数d
	int d=1;
	int temp=10;
	while(true)
	{
		
		if(max/temp>0)
		{
			d++;//次数加一
			temp*=10;
		}
		else
			break;
	}
	
	

	node head[10];//10个桶 

	int pos=1;//获取哪个位上的树,1表示个位

	while(d>=pos)
	{
		//依次把数组的数字放进相应桶里
		for(int i=0;i<len;i++)
		{
			int id=GetNumInPos(a[i],pos);
			head[id].key[head[id].count]=a[i];
			head[id].count++;
		}

		//依次从桶里去除数据赋值给a数组
		int num=0;
		for(int i=0;i<10;i++)
		{
			if(head[i].count!=0)
			{
				for(int j=0;j<head[i].count;j++)
				{
					a[num]=head[i].key[j];
					num++;
				}

				//清空桶
			    head[i].count=0;
			}
			
		}

		pos++;

		
	}
}
 
效率分析
平均时间复杂度:O(dn)(d即表示整形的最高位数)

空间复杂度:O(10n) (10表示0~9,用于存储临时的序列) 

稳定性:稳定

 

 

附上源代码地址:https://github.com/longpo/algorithm/tree/master/Combine

总结

至此,八大排序算法就学完了。



 

通常可以按平均时间将排序分为3类

1.平方阶O(n^2)排序,一般称为简单排序,如直接插入排序,直接选择排序和冒泡排序

2.线性对数阶O(nlog2(n))排序,如希尔排序,快速排序,堆排序和归并排序

3,。线性阶O(n)排序,如基数排序

各种排序的性能



 

没有哪一种排序方法是绝对好的。每一种排序方法都有优缺点,适合于不同的环境,因此,在实际应用中,应根据具体情况来做选择。

3
2
分享到:
评论
1 楼 fggsgigomkg 2015-04-05  
基数排序说的很好,理解了

相关推荐

    经典算法的C#源码实现

    经典排序算法 - 基数排序Radix sort 经典排序算法 - 鸽巢排序Pigeonhole sort 经典排序算法 - 归并排序Merge sort 经典排序算法 - 冒泡排序Bubble sort 经典排序算法 - 选择排序Selection sort 经典排序算法 - ...

    最快的排序算法 计算机最快的算法-史上14个最快速算法:孩子的计算能力爆表!大脑堪比计算机!...,排序算法数据结构

    在计算机科学领域中,排序算法是一种基本的算法,它可以将数据按照一定的顺序排列,以便更好地存储、检索和处理数据。排序算法的速度和效率对程序的性能有着至关重要的影响。 1.冒泡排序算法 冒泡排序算法是一种...

    8.12-8.19-冒泡-选择-插入-希尔-快速-归并-基数-堆排序-排序算法Swift代码及UI演示

    7. 基数排序(Radix Sort):基数排序是一种非比较型排序算法,通过按位数从低到高进行排序,适用于整数排序。它的复杂度可以达到线性O(nk),其中k是数字的最大位数。 8. 堆排序(Heap Sort):堆排序利用了堆这种...

    java排序算法-大全.rar

    8. **计数排序、桶排序、基数排序**:这些是线性时间复杂度的非比较型排序算法,适用于特定的数据分布情况,例如整数排序。 这个压缩包中的Java代码实现可以帮助我们深入理解这些算法的逻辑和细节,同时也可以作为...

    数字排序 - 排序算法 - 排序

    比较排序算法通过比较两个元素的大小来决定它们的顺序,典型的比较排序算法有冒泡排序、选择排序、插入排序、快速排序、归并排序和堆排序等。非比较排序则是通过直接计算出元素最终的位置来进行排序,如计数排序、...

    数据结构排序算法汇总包-直接插入排序 折半插入排序 2—路插入排序 表插入排序 希尔排序 起泡排序 快速排序 简单选择排序 树形选择排序 堆排序 归并排序链式基数排序

    实现以下常用的内部排序算法并进行性能比较:"直接插入排序"," 折半插入排序"," 2—路插入排序"," 表插入排序"," 希尔排序"," 起泡排序"," 快速排序"," 简单选择排序"," 树形选择排序"," 堆排序"," 归并排序"," 链式...

    归并排序,基数排序算法比较

    归并排序和基数排序是两种不同的排序算法,它们在实现方式和效率特点上存在显著差异。 **归并排序**是一种基于分治策略的排序算法。它的基本思想是将待排序的序列分成两个长度相等(或近似相等)的部分,分别对这两...

    各种查找与排序算法-笔试面试必备

    非比较排序算法如基数排序、桶排序和计数排序,不依赖于元素间的比较,而是利用了元素的固有特征进行排序,通常在特定条件下具有更高的效率。 #### 三、外部排序 外部排序涉及大量数据,通常超过内存容量,因此...

    排序算法 - Axb的自我修养1

    除此之外,还有其他一些排序算法,如归并排序,它采用分治策略,将数组分割成两半,分别排序后再合并,保证了稳定性,时间复杂度为O(N log N)。 在实际应用中,应根据数据规模、数据分布以及内存限制等因素选择合适...

    6种排序算法选择排序,冒泡排序,插入排序基数排序,快速排序,归并排序

    以下是对标题和描述中提及的六种排序算法的详细解析: 1. **选择排序(Selection Sort)** - 选择排序是一种简单直观的排序算法,它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在...

    数据结构--九种排序算法 --排序001.cpp

    此文件为数据结构中的九种排序算法,包含一些排序方法的过程,其九种排序包括:直接插入排序,折半插入排序,希尔排序,冒泡排序,快速排序,选择排序,堆排序,归并排序,基数排序!

    十大经典排序算法-多种编程语言

    十大经典排序算法 ... (2)排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部...常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序

    常见排序算法-C语言

    C语言实现常见排序算法。编译环境:VS2010。 包括: 冒泡排序 快速排序 直接插入排序 Shell排序 ...归并排序(递归和非递归两种) 桶式排序 基数排序:顺序和静态队列两种方法 索引排序(采用简单插入排序)

    排序算法-基于C语言实现的排序算法之RadixSort实现.zip

    尽管基数排序在小规模数据上可能不如其他高级排序算法(如快速排序、归并排序)快,但在处理大量数据时,其线性的运行时间优势非常明显。 总的来说,掌握基数排序不仅能够提升编程技能,还能够为处理大规模整数排序...

    java实现的排序算法-8个

    在编程领域,排序算法是计算机科学中的核心概念,特别是在数据处理和分析中起着至关重要的作用。Java作为一种广泛使用的编程语言,提供了丰富的工具和方法来实现各种排序算法。以下是基于给定的Java文件名(8种不同...

    归并排序、基数排序算法比较

    试通过随机数据比较归并排序、基数排序各算法的关键字比较次数和关键字移动次数。 (1)待排序表的表长不小于100;其中的数据要用伪随机数产生程序产生;至少要用5组不同的输入数据作比较;比较的指标为有。关键字...

    归并排序 基数排序 算法讲解

    总的来说,归并排序和基数排序各有优势,归并排序适用于大多数情况下的排序需求,而基数排序则在处理大量整数排序时展现出独特的优势。理解并掌握这两种排序算法,将有助于在实际问题中做出更合适的选择。

    排序算法-java实现

    8. **Timsort**:Timsort是Java、Python等语言内置的排序算法,结合了插入排序、归并排序和稳定排序的特点,特别适合处理已经部分有序的数组,其平均和最坏时间复杂度都是O(n log n)。 9. **Shell排序**(Shell ...

    算法-基础算法- 排序算法(包含源程序).rar

    8. 计数排序、桶排序和基数排序:这三种是线性时间复杂度的非比较排序算法,适用于特定类型的数据,如整数排序。它们不是比较元素之间的大小,而是利用数据特性进行排序。 了解并掌握这些排序算法有助于提升编程...

    排序算法(插入排序、交换排序、选择排序、归并排序、基数排序)

    本篇文章将详细解析五种常见的排序算法:插入排序、交换排序、选择排序、归并排序和基数排序,并探讨它们各自的特点和适用场景。 插入排序是一种简单直观的排序方法,它的工作原理是通过构建有序序列,对于未排序...

Global site tag (gtag.js) - Google Analytics