排序算法的评价评价排序算法的一般准则是:
▶ 平均情况下的排序速度
▶ 最优最劣情况下的速度
▶ 行为是否自然
▶ 是否以相等的关键字重排元素
数组的排序速度直接与比较(comparison)次数和交换(exchange)次数相关,其中交换的作用更大,因为占用的时间多。
如果频繁遭遇到最优最劣情况,则最优和最劣情况下的运行时间是重要的。
所谓自然(natural)行为的排序应该是,对已排序的表操作最容易,对失序越重的表操作越困难。
通常,如果有相等关键字的元素在排序前后,之间的相对位置并不改变,我们称之为该排序是稳定的。
气泡排序(bubble sort) 最著名(也最声名狼藉)的排序是气泡排序。
void bubble_sort(char *items, int count)
{
int i, j;
char t;
for(i = 1; i < count; i++)
{
for(j = count-1; j >= i; j--)
{
if(items[j-1] > items[j])
{
t = items[j-1];
items[j-1] = items[j];
items[j] = t;
}
}
}
}
分析:
两个 for 循环重复了比较的次数,所以比较的次数是恒定的:1 / 2(n平方 - n)
其中,外部循环执行 n - 1 次,内部循环执行 n/2 次,两式相乘得到以上公式。
下面是气泡排序的动画演示:
气泡排序动画演示选择排序(selection sort)选择排序中,先选择最小的元素并将其与第一个元素进行交换。然后剩余的 n - 1 个元素中选择最小值者并与第二个元素交换等,如此直到最后两个元素。
void select_sort(char *items, int count)
{
int i, j, k;
int exchange;
char t;
for(i = 0; i < count -1; i++)
{
exchange = 0;
t = items[i];
k = i;
for(j = i+1; j < count; j++)
{
if(items[j] < t)
{
t = items[j];
k = j;
exchange = 1;
}
}
if(exchange)
{
items[k] = items[i];
items[i] = t;
}
}
}
分析:
和气泡算法一样,选择排序需要进行的比较次数同样为 1/2 (n平方 - n) 。尽管如此,但在平均情况下,选择排序的交换次数要少得多。
下面是选择排序的动画演示:
选择排序动画演示插入排序(Insertion sort)插入排序中,先对前两个元素进行排序,然后把第三个元素按序插入到已排好序的前两个元素中。随后是第四个插入到已排好序的前三个元素中,以此类推,直到所有元素都有序为止。
void insert_sort(char *items, int count)
{
int i, j;
char t;
for(i = 1; i < count; i++)
{
t = items[i];
j = i - 1;
while(j >= 0 && items[j] > t)
{
items[j+1] = items[j];
j--;
}
items[j+1] = t;
}
}
分析:
与气泡排序和选择排序不同的是,插入排序的比较次数与被排表的初始排列有关。如果表是完全有序的,比较 n - 1 次,否则按 n 平方次进行。
因此,最劣情况下,与 气泡排序和选择排序一样差,平均情况稍好一点。然而这种办法的确有两个优点:
1. 排序是自然的,即表已排序时工作量最少,反序时工作量最大。这样,对基本已排序的表操作时,插入排序是最理想的。
2. 排序是稳定的,即相同关键字元素的相对位置,排序前后保持不变。
下面是插入排序的动画演示:
插入排序动画演示前面几个算法,执行时间都是 n 平方级的,对于大量数据而言,排序速度非常慢,有时会完全不实用。
下面是两个较快的算法
希尔排序(Shell sort)希尔排序是根据其发明者的名字(D.L.Shell)命名的。其一般方法是从插入排序导出并基于增量减少 (diminishing increments)。例如,首先,对间隔三个位置的元素排序;然后,再对间隔两个位置的元素排序;最后,对相邻元素进行排序。
排序的每一遍涉及相对较少的元素或已恰当排序的元素。因此,希尔排序是高效的,每一遍都提高了有序性。
增量的准确序列可以变化,唯一规则是最后增量必须为 1 。例如:9 ,5, 3, 2, 1 。以 2 的幂为增量值的序列是不可取的,出于复杂的数学原理,这种序列降低了排序算法的效率。
void shell_sort(char *items, int count)
{
int i, j, k, gap;
int gaps[5];
char t;
gaps[0] = 9; gaps[1] = 5; gaps[2] = 3; gaps[3] = 2; gaps[4] = 1;
for(k = 0; k < 5; k++)
{
gap = gaps[k];
for(i = gap; i < count; i++)
{
t = items[i];
j = i - gap;
while(j >= 0 && items[j] > t)
{
items[j+gap] = items[j];
j = j - gap;
}
items[j+gap] = t;
}
}
}
分析:
希尔排序的执行与 n 的1.2 次方 成比例,相对于 n 平方排序而言,这是重大改进。
下面是希尔排序动画演示:
希尔排序动画演示快速排序(quick sort)快速排序是又 C.A.R.Hoare 发明的,一般被认为是目前最好的通用排序算法。快速排序基于交换排序,与同样基于交换排序的 气泡排序相比,其效果是惊人的。
快速排序的基本思想是分区(partition)。一般过程是先选一个比较数(comparand)的值,然后把数组分成两段。大于等于分区值的元素都放在一边,小于分区值的元素放在另一边。然后对数组的另一段重复上述过程,直到该数组完成排序。
排序的过程本质上递归的,而实际上,快速排序的最清晰实现就是递归算法。
选择比较数值的办法有两个,可以随机选取也可以选取数组中一组值求平均值得到。
void quick_sort(char *items, int count)
{
qs(items, 0, count - 1);
}
void qs(char *items, int left, int right)
{
int i, j;
char x, t;
i = left; j = right;
x = items[(left+right)/2];
do
{
while(items[i] < x && i < right)
i++;
while(x < items[j] && j > left)
j--;
if(i <= j)
{
t = items[i];
items[i] = items[j];
items[j] = t;
i++; j--;
}
}while(i <= j);
if(left < j)
qs(items, left, j);
if(i < right)
qs(items, i, right);
}
分析:
快速排序的平均比较次数为 n log n ,近似交换次数 n/6 log n 。这两个数值远小于前面各种排序的相应参数。
需要注意的一个问题是,如果每个分区的比较数值选择了最大值,快速排序退化成 n 平方操作时间的排序。
快速排序是分而治之(divide and conqer)的策略,请参考另外一种采用 分治 策略的排序方法:
归并排序(Merge Sort)(zz) 。
与归并排序不同的是, 最劣情况下,快速排序的的时间复杂度为 n 平方,而归并排序则是 nlogn 。这里的这个算法写的不够清晰,请参看
寻找第k小的数 与 快速排序
相关推荐
《十大经典排序算法总结》 排序算法是计算机科学的基础,其设计思想和效率对软件的性能有着直接影响。本文主要探讨了十种经典的排序算法,包括它们的设计思路、优缺点以及适用场景,帮助我们理解排序算法的核心。 ...
C#排序算法总结涵盖了交换排序和插入排序两大类排序算法,其中交换排序包括了冒泡排序、选择排序和快速排序,而插入排序则涉及直接插入排序和折半插入排序。下面将详细介绍每种排序算法的实现原理、特点以及在C#中的...
【排序算法总结】 排序是计算机科学中的一项基本操作,它涉及到如何有效地重新排列一组数据,使其按照特定的顺序排列。本文将重点介绍八大排序算法,包括插入排序、希尔排序、交换排序、快速排序、选择排序、堆排序...
本文将对几种常见的内部排序算法和外部排序算法进行详细总结。 首先,排序的基本定义是:给定一个包含n个记录的序列,其关键字序列分别为K1, K2, ..., Kn,如果存在一个排列p1, p2, p3, ..., pn,使得关键字满足非...
在这个名为“各种排序算法总结(ppt)”的资料中,我们将会深入探讨多种常见的排序算法,包括它们的基本原理、优缺点以及实际应用。** 首先,我们要了解排序的目的是为了使数据有序,这在数据处理和分析中具有广泛...
【排序算法总结】 排序算法是计算机科学中处理数据排列的重要工具,主要分为稳定排序和非稳定排序、内排序和外排序两大类。稳定排序保证了相同元素在排序后的相对位置不变,而非稳定排序则不作此保证。内排序是指...
根据提供的信息,我们可以总结出以下关于八种基本排序算法中的两种——冒泡排序(Bubble Sort)与插入排序(Insert Sort)的知识点。 ### 冒泡排序(Bubble Sort) #### 定义 冒泡排序是一种简单的排序算法。它...
### 常用排序算法总结 #### 一、冒泡排序 冒泡排序是一种简单的排序算法,它重复地遍历待排序的数列,依次比较相邻的两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复进行的,直到没有再需要...
排序算法是计算机科学中最基础且重要的算法之一,用于将一组数据按照特定顺序排列。这里我们主要探讨五种经典的排序算法:选择排序、冒泡排序、插入排序、快速排序以及归并排序。 1. **选择排序**: 选择排序的...
在本篇总结中,将探讨8种经典的排序算法,分别是冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序、二叉树排序和基数排序。 1. 冒泡排序(Bubble Sort): 冒泡排序是一种简单的排序算法。它重复地遍历要...
八大经典排序算法总结和源代码 在计算机科学中,排序算法是最基本也是最重要的算法之一。排序算法的性能直接影响到整个系统的性能。今天,我们将总结八大经典排序算法,并提供C++实现的源代码。 一、稳定排序和...
排序算法总结——最全、最新的排序算法 本文对各种排序算法进行了总结,包括插入排序、选择排序、冒泡排序、快速排序和堆排序等。下面是对每种排序算法的详细介绍: 一、插入排序(Insertion Sort) 插入排序是一...
本文将对数据结构常见的八大排序算法进行详细阐述,包括它们的基本思想、工作原理以及适用场景。 1. 直接插入排序: 直接插入排序是一种简单直观的排序算法,它的工作原理类似于我们平时手动排序扑克牌。首先,假设...
排序算法是计算机科学中的一种基本算法,用于对数据进行排序。在各种排序算法中,每种算法都有其特点和应用场景。本文将对10种经典的排序算法进行总结,并对每种算法的时间复杂度、空间复杂度和适用场景进行分析。 ...
### 几种内部排序算法总结 #### 冒泡排序(Bubble Sort) 冒泡排序是一种简单的排序算法,它重复地遍历待排序的数列,依次比较相邻的两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复进行的,...
冒泡排序和快速排序是两种基础但广泛使用的数据排序算法。冒泡排序由于其简单直观的特性,易于理解和实现,而快速排序则以其较高的效率在数据量较大时展现出优势。 首先,让我们来看冒泡排序算法。冒泡排序通过重复...
C++数据结构排序算法总结 在计算机科学中,排序算法是最基本和最重要的算法之一。在实际应用中,排序算法广泛应用于各种领域,如数据分析、机器学习、数据库管理等。C++数据结构排序算法总结将为您提供详细的排序...