排序

废话不多说,排序:

1,排序分类:可以再内存中一次排序完成,叫做内排序;要分批进入(内存太小)叫做外排序;

   内排序按所用策略不同又分为5大类:插入,选择,交换,归并和分配排序;

其中, 插入排序主要包括 直接插入排序希尔排序两种; 选择排序主要包括 直接选择排序堆排序交换排序主要包括气(冒)泡排序和 快速排序
   
 排序又有稳定与不稳定之分:
稳定排序:假设在待排序的文件中,存在两个或两个以上的记录具有相同的关键字,在
用某种排序法排序后,若这些相同关键字的元素的相对次序仍然不变,则这种排序方法
是稳定的。其中冒泡,插入,基数,归并属于稳定排序,选择,快速,希尔,堆属于不稳定排序。
按照需不需要辅助空间又可以分为:
就地排序:若 排序算法所需的辅助空间并不依赖于问题的规模n,即辅助空间为O(1),
则称为就地排序。

2,现在按照策略不同来详细介绍各种排序法:
   a,插入排序:
    a1:直接插入排序:
   
每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
第一趟比较前两个数,然后把第二个数按大小插入到有序表中; 第二趟把第三个数据与前两个数从前向后扫描,把第三个数按大小插入到有序表中;依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
直接插入排序属于稳定的排序,最坏 时间复杂性为Θ(n^2), 空间复杂度为O(1)。
直接插入排序是由两层嵌套循环组成的。外层循环标识并决定待比较的数值。内层循环为待比较数值确定其最终位置。直接插入排序是将待比较的数值与它的前一个数值进行比较,所以外层循环是从第二个数值开始的。当前一数值比待比较数值大的情况下继续循环比较,直到找到比待比较数值小的并将待比较数值置入其后一位置,结束该次循环。
值得注意的是,我们必需用一个 存储空间来保存当前待比较的数值,因为当一趟比较完成时,我们要将待比较数值置入比它小的数值的后一位 插入排序类似玩牌时整理手中纸牌的过程。插入排序的基本方法是:每步将一个待排序的记录按其关键字的大小插到前面已经排序的序列中的适当位置,直到全部记录插入完毕为止。
C/C++代码实现直接插入排序:
void insert_sort(int a[], int n)
{
int i, j, temp;
for (i = 1; i < n; ++i)
{
temp = a[i];
for (j = i; j>0 && temp < a[j - 1]; --j)
{
a[j] = a[j - 1];
}
a[j] = temp;
}
}
a2:希尔排序(分组插入排序:注意他为不稳定排序)
希尔排序思想:分组插入的思想,加入有5个数a[0]-a[4],那么第一轮比较a[2],a[0],a[4],  a[1]和a[3];  第二轮比较相邻的元素;为什么比较a[0],a[2],a[4]因为先取步长为5/2~=2;  a[0],a[2],a[4]相隔2;
void ShellSort(int a[], int n)
{
int d, i, j, temp;
for(d = n/2;d >= 1;d = d/2)
{
for(i = d; i < n;i++)
{
temp = a[i];
for(j = i - d;(j >= 0) && (a[j] > temp);j = j-d)
{
a[j + d] = a[j];
}
a[j + d] = temp;
}
}
}

优劣

不需要大量的辅助空间,和 归并排序一样容易实现。希尔排序是基于 插入排序的一种算法, 在此算法基础之上增加了一个新的特性,提高了效率。希尔排序的 时间复杂度为 O(N*(logN)2), 没有 快速排序算法快 O(N*(logN)),因此中等大小规模表现良好,对规模非常大的 数据排序不是 最优选择。但是比O(N2)复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。 此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏 的情况下执行的效率会非常差。 专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快, 再改成快速排序这样更高级的 排序算法. 本质上讲,希尔排序算法的一种改进,减少了其复制的次数,速度要快很多。 原因是,当N值很大时 数据项每一趟排序需要的个数很少,但数据项的距离很长。 当N值减小时每一趟需要和动的数据增多,此时已经接近于它们排序后的最终位置。 正是这两种情况的结合才使希尔排序效率比 插入排序高很多。
b,选择排序:
b1:直接选择排序:基本思想: 直接选择排序(Straight Select Sorting) 也是一种简单的排序方法,它的基本思想是:第一次从R[0]~R[n-1]中选取最小值,与R[0]交换,第二次从R{1}~R[n-1]中选取最小值,与R[1]交换,....,(很适合一般人的想法)
直接选择排序:(不稳定排序)
void SelectSort(int R[], int n)
{
int i, j;
int t;
for(i=0; i<n-1; i++)
{
//m = i;
for(j = i+1; j < n; j++)
{
if(R[j] < R[i])




{
t = R[i];


R[i] = R[j];
R[j] = t;
}
}
}
}
优劣:
在直接选择排序中,共需要进行n-1次选择和交换,每次选择需要进行 n-i 次比较 (1<=i<=n-1),而每次交换最多需要3次移动,因此,总的比较次数C=1/2(n*n - n),
总的移动次数 3(n-1).由此可知,直接选择排序的 时间复杂度为 O(n2) (n的平方),所以当记录占用字节数较多时,通常比 直接插入排序的执行速度快些。
b2:堆排序:不稳定排序:http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html
这个不多说了,有点复杂,可以参看上面的网址,博主写的很好;
C:交换排序:
c1:冒泡排序:
思想:
已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。首先比较a[1]与a[2]的值,若a[1]大于a[2]则交换两者的值,否则不变。再比较a[2]与a[3]的值,若a[2]大于a[3]则交换两者的值,否则不变。再比较a[3]与a[4],以此类推,最后比较a[n-1]与a[n]的值。这样处理一轮后,a[n]的值一定是这组数据中最大的。再对a[1]~a[n-1]以相同方法处理一轮,则a[n-1]的值一定是a[1]~a[n-1]中最大的。再对a[1]~a[n-2]以相同方法处理一轮,以此类推。共处理n-1轮后a[1]、a[2]、……a[n]就以升序排列了。降序排列与升序排列相类似。

//4冒泡:
void BubleSort(int a[],int N)
{
int t;
for(int i=0;i<N;i++)
{
for(int j=0;j<N-i;j++)
if(a[j]>a[j+1])
{
// a[j] = a[j]^a[i];
// a[i] = a[j]^a[i];
// a[j] = a[j]^a[i];
t=a[j];
a[j]=a[j+1];
a[j+1]=t;


}
}
}
优点:稳定;
缺点:慢,每次只能移动相邻两个数据

c2:快速排序:
//5快速排序:
int Partition(int R[],int i,int j)//
    {//调用Partition(R,low,high)时,对R[low..high]做划分,
     //并返回基准记录的位置
      int pivot=R[i]; //用区间的第1个记录作为基准 '
      while(i<j){ //从区间两端交替向中间扫描,直至i=j为止
        while(i<j&&R[j]>=pivot) //pivot相当于在位置i上
          j--; //从右向左扫描,查找第1个关键字小于pivot.key的记录R[j]
        if(i<j) //表示找到的R[j]的关键字<pivot.key
            R[i++]=R[j]; //相当于交换R[i]和R[j],交换后i指针加1
        while(i<j&&R[i]<=pivot) //pivot相当于在位置j上
            i++; //从左向右扫描,查找第1个关键字大于pivot.key的记录R[i]
        if(i<j) //表示找到了R[i],使R[i].key>pivot.key
            R[j--]=R[i]; //相当于交换R[i]和R[j],交换后j指针减1
       } //endwhile
      R[i]=pivot; //基准记录已被最后定位
      return i;
    } //partition 

排序数组A的值分别是:(初始关键数据: key=49) 注意关键 key永远不变,永远是和 key进行比较,无论在什么位置,最后的目的就是把 key放在中间,小的放前面大的放后面。
A[0]
A[1]
A[2]
A[3]
A[4]
A[5]
A[6]
49
38
65
97
76
13
27
进行第一次交换后:27 38 65 97 76 13 49
( 按照算法的第三步从后面开始找,此时:J=6)
进行第二次交换后:27 38 49 97 76 13 65
( 按照算法的第四步从前面开始找> key的值,65>49,两者交换,此时:I=2 )
进行第三次交换后:27 38 13 97 76 49 65
( 按照算法的第五步将又一次执行算法的第三步从后开始找
进行第四次交换后:27 38 13 49 76 97 65
( 按照算法的第四步从前面开始找大于 key的值,97>49,两者交换,此时:I=3,J=5 )
此时再执行第三和四步的时候就发现I=J=4,从而结束一趟快速 排序,那么经过一趟快速排序之后的结果是:27 38 13 49 76 97 65,即所有大于 key49的数全部在49的后面,所有小于 key(49)的数全部在 key(49)的前面。



void QuickSort(int R[],int low,int high)
   { //对R[low..high]快速排序
     int pivotpos; //划分后的基准记录的位置
     if(low<high){//仅当区间长度大于1时才须排序
        pivotpos=Partition(R,low,high);// //对R[low..high]做划分
        QuickSort(R,low,pivotpos-1); //对左区间递归排序
        QuickSort(R,pivotpos+1,high); //对右区间递归排序
      }
    } //QuickSort








   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值