基础排序算法个人小结(未完待续).md

一.插入排序(O(N2))

1.1算法分析
    插入排序由N-1趟排序组成,对于p=1趟到p=N-1趟,插入排序保证从位置0到位置p上的元素为已排序状态。插入排序利用了这样的事实:位置0到  
    位置p-1上的元素是已经排序过的。
关于插入排序的定理:N个互异数的数组的平均逆序数式N(N-1)/4,这也是排序过程中需要交换的总次数。
1.2代码示例

实例代码如下所示:

//以下为插入排序算法示例
#include<iostream>
using namespace std;
#define M 6
void InsertionSort(int Int[], int);
int main()
{
    int i;
    int Integer[M] = { 34,8,64,51,32,21 };
    cout << "排序前:";
    for (int i = 0; i < M; i++)
    cout<<Integer[i]<<"   ";
        cout<<endl;
    InsertionSort(Integer,M);
    cout << "排序后:";
    for (int i = 0; i < M; i++)
    cout<<Integer[i] << "   " ;
    getchar();
    return 0;
}
void InsertionSort(int Int[], int N)//排序算法函数主体
{
    int j, p;
    int tmp;
    for (p = 1; p < M; p++)
    {
        tmp = Int[p];
        for (j = p; j > 0 && Int[j - 1] > tmp; j--)
            Int[j] = Int[j - 1];
            Int[j] = tmp;
    }
}
1.3插入排序运行结果截图

这里写图片描述

二.希尔排序(O(N2))

2.1算法分析
    希尔排序(ShellSort)的名称源于它的发明者Donald Shell,该算法通过比较相距一定的间隔的元素来工作;各趟比较所用的距离随着算法的  
    进行而减小,直到只比较相邻元素的最后一趟排序位置。因此,有时也叫缩小增量排序。
希尔排序使用一个增量序列,h1,h2……..hk ,且经过增量hk排序一趟的文件,称为是hk-排序的。希尔排序的一个重要性质是,一个hk-排序的文件(此后将是hk-1-排序的)保持它的hk-排序性能。通俗的说就是,后面的排序不会打乱前面具有的排序性。

增量序列的一种流行(但是不太好)的选择是使用Shell建议的序列:ht=[ N/2 ]和hk = [ hk+1/2 ]。
关于希尔排序的定理:—————–>
*.使用希尔增量(hk +1= [ hk+1/2 ])时希尔排序的最坏情形运行时间为Θ(N^2).
*.使用Hibbard增量(hk+2=2hk+1+1)的希尔排序的最坏情形运行时间为Θ(N^3/2).
2.2代码示例
//以下为希尔排序算法示例
#include<iostream>
using namespace std;
#define M 13
void ShellSort(int Int[], int);
int main()
{    int i;
    int Integer[M] = { 81,94,11,96,12,35,17,95,28,58,41,75,15};
        cout << "排序前:";
    for (int i = 0; i < M; i++)
        cout<<Integer[i]<<"   ";
        cout<<endl;
    ShellSort(Integer,M);
        cout << "排序后:";
    for (int i = 0; i < M; i++)
        cout<<Integer[i] << "   " ;
    getchar();
    return 0;
}
void ShellSort(int Int[], int N)
{
    int i, j, Increment;
    int tmp;
    for (Increment = N/2; Increment > 0; Increment /= 2)//流行的希尔增量为N/2
        for(i = Increment; i < N; i++)
    {
            tmp = Int[i];
            for (j = i; j >= Increment; j -= Increment)
                if (tmp < Int[j - Increment])
                    Int[j] = Int[j - Increment];
                else
                    break;
            Int[j] = tmp;
    }
}
2.3希尔排序运行结果截图

这里写图片描述

三.堆排序(2NlogN-O(N))

3.1算法分析
 关于堆:
      *.堆(heap)是一颗被完全填满的二叉树,有可能的例外是在底层,底层的元素从左到右填入,这样的树也称为完全二叉树。
      *.堆的结构:完全二叉树由于其规律性,可以用数组来实现而不用指针。对于数组中任一位置i上的元素,其左儿子在位置2i上,右  
      儿子在左儿子后的单元(2i+1)中,它的父亲则在位置[i/2]上。
      *.堆具有堆序性:根上的元素应该是最小/大元,且我们考虑任意子树也应该是一个堆,那么任意节点就应该小于/大于它的所有后裔。

     在介绍堆的章节,提到过堆(即优先队列)可以用于花费O(NlogN)时间的排序(该方法需要再开辟一个数组),是目前为止的最佳的大O运行时间。
     在实例实现过程中,将使用一个(Max)堆,但由于速度的原因避免了实际的ADT。按照通常习惯,每一件事都是在数组中完成的。第一步以线性  
     时间建立一个堆。然后通过将堆中的最后元素与第一个元素交换,缩减堆的大小并进行下滤,来执行N-1次DeleteMax操作。当算法终止时,数组  
     则以所排的顺序包含这些元素。
3.2代码示例
#include<iostream>
using namespace std;
#define LeftChild(i) (2*(i)+1)
#define M 7
void PercDown(int Int[], int i, int N);
void HeapSort(int Int[], int N);
int Swap(int *p, int *q);
int  main()
{
    int Integer[M] = { 31,41,59,26,53,97,58 };
    cout << "排序前:";
    for (int i = 0; i < M; i++)
        cout<<Integer[i]<<"   ";
        cout << endl;
    HeapSort(Integer, M);
    cout << "排序后:";
    for (int i = 0; i < M; i++)
        cout << Integer[i] << "   ";
        cout << endl;
    getchar();
}
void PercDown(int Int[], int i, int N)//下滤操作,堆的空穴向下移动
{
    int Child;
    int tmp;
    for (tmp = Int[i]; LeftChild(i) < N; i = Child)
    {
        Child = LeftChild(i);
        if (Child != N - 1 && Int[Child + 1] > Int[Child])
            Child++;
        if (tmp < Int[Child])
            Int[i] = Int[Child];
        else
            break;
    }
    Int[i] = tmp;
}
void HeapSort(int Int[], int N)
{
    int i;
    for (i = N/2; i >= 0; i--)   //Build Heap操作
        PercDown(Int, i, N);
    for (i = N - 1; i > 0; i--)
    {
        Swap(&Int[0], &Int[i]);//Delete Max操作
        PercDown(Int, 0, i);
    }
}
int Swap(int *p, int *q)//swap函数注意形参传入不要出错
{
    int temp;
    temp = *p;
    *p = *q;
    *q = temp;
    return 0;
}
3.3堆排序运行结果截图

这里写图片描述


四.归并排序(O(NlogN))

4.1算法分析
   *.归并排序以O(NlogN)最坏情形运行时间运行,是递归算法的一个很好的实例。
   *.这个算法的基本操作是合并两个已排序的表。因为这两个表示已经排序好的,所以若将输出放到第三个表中时则该算法可以通过对输入数据一趟  
   排序来完成。
   *.该算法是经典的分治策略,它将问题分成一些小问题然后递归求解,然后将各个阶段解得的答案修补到一起。
   *.虽然归并排序的运行时间是O(NlogN),但是它很难用于主存排序,主要问题在于合并两个排序的表需要线性附加内存,在整个算法中还要花  
   费将数据拷贝到临时组再拷贝会来这样这样一些附加的工作,其结果严重放慢了排序的速度。
4.2代码示例
#include<stdio.h>
#include<stdlib.h>
#include<time.h>       //突然想看看运行时间如何,就加了time测试,多组数据实验表明归
                // 并排序较快而且非常稳定(10ms以内),插入排序相对比较慢而且逆序数不一样还会更慢
#define M 13
void Msort(int Integer[], int TmpArray[], int left, int right);
void MergeSort(int Integer[], int N);
void Merge(int Integer[], int TmpArray[], int lpos, int rpos, int rightend);
int main()
{
    int i; 
    time_t time_count_begin;
    time_t time_count;
    time_count_begin = clock();
    int Integer[M] = { 81,94,11,96,12,35,17,95,28,58,41,75,15 };
    printf("排序前:");
    for (int i = 0; i < M; i++)
        printf("%d  ", Integer[i]);
    printf("\n");
    MergeSort(Integer, M);
    printf("排序后:");
    for (int i = 0; i < M; i++)
        printf("%d  ", Integer[i]);
    time_count = (clock()-time_count_begin)*1000/CLOCKS_PER_SEC;
    printf("\n所需时间为%d毫秒  ", time_count);
    getchar();
    return 0;
}
void Msort(int Integer[], int TmpArray[], int left, int right)
{
    int center;
    if (left < right)
    {
        center = (left + right) / 2;
        Msort(Integer, TmpArray, left, center);
        Msort(Integer, TmpArray, center+1, right);
        Merge(Integer, TmpArray, left, center+1,right);
    }
}
void MergeSort(int Integer[], int N)
{
    int *TmpArray;
    TmpArray = malloc(N * sizeof(int));
    if (TmpArray != NULL)
    {
        Msort(Integer, TmpArray, 0, N - 1);
        free(TmpArray);
    }
    else
        printf("No space for tmp array!!");
}
//lpos= 左半边的起始点      rpos=右半边的起始点
void Merge(int Integer[], int TmpArray[], int lpos, int rpos, int rightend)
{
    int i, leftend, NumElements, tmpos;
    leftend = rpos - 1;
    tmpos = lpos;
    NumElements = rightend - lpos + 1;
    //主循环
    while (lpos <= leftend && rpos <= rightend)
        if (Integer[lpos] <= Integer[rpos])
            TmpArray[tmpos++] = Integer[lpos++];
        else
            TmpArray[tmpos++] = Integer[rpos++];
    while (lpos <= leftend) //拷贝剩余的第一部分
        TmpArray[tmpos++] = Integer[lpos++];
    while (rpos <= rightend) //拷贝剩余第二部分
    {
        TmpArray[tmpos++] = Integer[rpos++];
    }
    //将Tmparray拷贝回去
    for (i = 0; i < NumElements; i++, rightend--)
        Integer[rightend] = TmpArray[rightend];
}
4.3归并排序运行结果截图

这里写图片描述


五、快速排序(O(N2))

5.1算法分析
 快速排序的平均复杂度为O(NlogN),稍加努力(选取合适的枢纽元)就可以做到,并且避免最坏情形。将数组S快速排序分为以下四步:

*.如果S中元素个数是0或者1,则返回;
*.取S中任一元素v,称之为枢纽元(或基准数)pivot;
*.将S-{v}(S中其余元素)分成两个不相交的集合:S1={x∈S-{v}|x≤v}和S2={x∈S-{v}|x≥v};
*.返回QucikSort(S1)后,继而v,继而QucikSort(S2)。

5.2代码示例
#include <stdio.h>
#define M 12
void quicksort(int Int[],int left, int right)
{
    int i, j, t, temp;
    if (left>right)
        return;
    temp = Int[left]; //temp中存的就是基准数
    i = left;
    j = right;
    while (i != j)
    {
        //顺序很重要,要先从右边开始找
        while (Int[j] >= temp && i<j)
            j--;
        //再找左边的
        while (Int[i] <= temp && i<j)
            i++;
        //交换两个数在数组中的位置
        if (i<j)
        {
            t = Int[i];
            Int[i] = Int[j];
            Int[j] = t;
        }
    }
    //最终将基准数归位
    Int[left] = Int[i];
    Int[i] = temp;

    quicksort(Int,left, i - 1);//继续处理左边的,这里是一个递归的过程
    quicksort(Int,i + 1, right);//继续处理右边的 ,这里是一个递归的过程
}
int main()
{
    int i, j, t;
    int Integer[M] = { 81,94,11,96,12,28,58,15,32,100,-22.5,12 };
    printf("快速排序前:");                //输出排序后的结果
    for (i = 0; i < M; i++)
        printf("%4d ", Integer[i]);
    quicksort(Integer, 0, M - 1); //快速排序调用
    printf("\n快速排序后:");                //输出排序后的结果
    for (i = 0; i < M; i++)
        printf("%4d ", Integer[i]);
    getchar(); getchar();
    return 0;
}
5.3快速排序运行结果截图

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值