排序算法总结

/*冒泡排序
 *思路:比较相邻的前后二个数据,如果前面数据大于后面的数据,
 *就将二个数据交换。这样对数组的第0个数据到N-1个数据进行一次遍历后,
 *最大的一个数据就“沉”到数组第N-1个位置。 N=N-1,如果N不为0就重复前面二步,
 *否则排序完成。
 **/
void BubbleSort1(int a[], int n)
{
    int i, j;
    for (i = 0; i < n;i++)
    {
        for (j = 0; j < n - i; j++)
        {
            if (a[j - 1]>a[j])
            {
                swap(a[j - 1], a[j]);
            }
        }
    }
}
/*
 *冒泡优化版
 *思路:如果这一趟牌靴发生了交换,则说明排序没有完成 ,如果没有发生交换,说明排序已经完成;
 *对于一个数组如果前20个无序,后80个都是有序的,那么经过一次遍历之后,我们每次只需要记录下他最后一次
 *交换的位置,那么我们下一次遍历的时候只需要遍历到那个位置就可以了。
 **/
void  BubbleSort2(int a[], int n)
{
    int i, j;
    int temp = n;
    while (temp > 0)
    {
        i = temp;
        temp = 0;
        for (j = 1; j < i;j++)
        {
            if (a[j-1] > a[j])
            {
                swap(a[j-1],a[j]);
                temp = j;
            }
        }
    }
}
/*
 *                      直接插入排序的三种实现
 *直接插入的基本思想:每次将一个带排序的数组,暗器关键字大小,插入到前面已经排好序的子序列中的适当位置,
 *直到全部记录插入完成为止。
 *1: 初始时:a{0}自成1个有序去,无序区为a[1...n-1], 令 i= 1;
 *2:将a[i]并入当前的有序区,a[0,...i-1]中形成a[a,...i]的有序区间;
 *3:i++ 并重复第二步直到i ==n-1.排序完成;
 **/
void Insertsort1(int a[], int n)
{
    int i, j, k;
    for (i = 1; i < n;i++)
    {
        //为a[i]在前面的a[0,i-1]有序区间中找一个合适的位置。
        for (j = i - 1; j >= 0; j--)
        {
            if (a[j]<a[i])
            {
                break;
            }
        }
        //如找到了一个合适的位置。
            if (j != i-1 )
            {
                int temp = a[i];
                //将比a[i]大的数据后移
                for (k = i - 1; k> j;k--)
                {
                    a[k + 1] = a[k];
                }
                //将a[i]放到正确的位置上
                a[i-1 ] = temp;
            }
    }
}
/*
 *即每次a[i]先和前面一个数据a[i-1]比较,如果a[i] > a[i-1]说明a[0…i]也
 *是有序的,无须调整。否则就令j=i-1,temp=a[i]。然后一边将数据a[j]向后移动一
 *边向前搜索,当有数据a[j]<a[i]时停止并将temp放到a[j + 1]处
 **/
void Insertsort2(int a[], int n)
{
    int i, j;
    for (i = 1; i < n;i++)
    {
        if (a[i] <a[i-1])
        {
            int temp = a[i];
            for (j = i - 1; j >= 0 && a[j]>temp;j--)
            {
                a[j + 1] = a[j];
            }
            a[j] = temp;
        }
    }
}
/*
 *如果a[j]前一个数据a[j-1] > a[j],就交换a[j]和a[j-1],再j--直到
 * a[j-1] <= a[j]。这样也可以实现将一个新数据新并入到有序区间。
 **/
void Insertsort3(int a[], int n)
{
    int i, j;
    for (i = 1; i < n;i++)
    for (j = i - 1; j >= 0 && a[j]>a[j + 1]; j--)
        swap(a[j],a[j+1]);
 }
/*                 希尔排序
 *排序的基本思想是:先将整个带排序元素序列分割成若干个子序列,分别进行直接插入排序,
 *然后依次缩减增进量,再进行排序,当增量足够小的是, 整体元素基本有序, 在进行一次,
 *直接插入排序。因为,直接插入排序在基本有序的情况下效率是很高的,因此,希尔排序在时间效率上
 *也是很高的。
 */
void ShellSort1(int a[], int n)
{
    int i,j, gap;
    for (int gap = n / 2; gap > 0; gap--)//步长
    {
        for (i = 0; i < gap;i++)         //安组排序
        {
            for (j = i + gap; j < n; j+= gap)
            {
                if (a[j] < a[j-gap])
                {
                    int temp = a[j];
                    int k = j - gap;
                    while (k>=0&&a[k]>temp)
                    {
                        a[k + gap] = a[k];
                        k -= gap;
                    }
                    a[k + gap] = temp;
                }
            }
        }
    }
}
void ShellSort2(int a[], int n)
{
    int j, gap;
    for ( gap = n/2; gap >  0; gap/=2)
    {
        for (j = gap; j < n;j++)    //从数组第gap个元素开始
        {
            if (a[j] < a[j-gap])    //每个元素与自己组内的数据进行直接插入排序
            {
                int temp = a[j];
                int k = j - gap;
                while (k>=0&&a[k]>temp)
                {
                    a[k + gap] = a[k];
                    k -= gap;
                }
                a[k + gap] = temp;
            }
        }
    }
}
/*
 *用直接插入发的第三种方法来改写如下:
 **/
void shellSort3(int a[], int n)
{
    int i, j, gap;
    for (gap = n / 2; gap > 0; gap / 2)
    {
        for (i = gap; i < n;i++)
        {
            for (j = i - gap; j >= 0 && a[j]>a[j + gap];j-=gap)
            {
                swap(a[j], a[j + 1]);
            }
        }
    }
}
/*                 直接选择排序
 *直接选择排序是从无序区选一个最小的元素直接放到有序区的最后
 *设数组为 a[0…n-1]。
 *初始时,数组全为无序区为 a[0..n-1]。令 i=0
 *在无序区 a[i…n-1]中选取一个最小的元素, 将其与 a[i]交换。 交换之后 a[0…i]
 *就形成了一个有序区。
 *i++并重复第二步直到 i==n-1。排序完成。
 **/
void SelectSortt(int a[], int n)
{
    int i, j, nMinIndex;
    for (i = 0; i < 0;i++)
    {
        nMinIndex = i;//
        for (j = i + 1; j < n;j++)
        {
            if (a[j] < a[nMinIndex])
            {
                nMinIndex = j;
            }
        }
        Swap(a[i],a[nMinIndex]);
    }
}
/*          归并排序
 *算法思想: 采用分治的典型应用;
*/
/*
 *将两个有序数列合并。思路:只要将两个有序数列进行比较,将小的取出,然后在对应数列中删除取出的数
 *然后在进行比较,如果有数列为空,那么把另一个数列中剩余的数全部取出即可;
 **/
int MergeSortArray (int a[], int n, int b[], int m, int c[])
{
    int i, j, k;
    i = j = k = 0;
    while (i < n&&j < m)
    {
        if (a[i] <b[j])
        {
            c[k++] = a[i++]
        }
        else
        {
            c[k++] = b[j++];
        }
    }
    while (i < n)
    {
        c[k++] = a[i++];
    }
    while (j<m)
    {
        c[k++] = b[j++];
    }
}
/*          归并排序
*基本思路就是将数组分成二组 A,B,如果这二组组内的数据都是有序的,进行上面的操作,首先要使A,B有序
*可以将 A,B 组各自再分成二组。依次类推,当分出来的小组只有一个数据时,
*可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。
*/
bool MergeSort(int a[], int n)
{
    int *pTempArray = new int[n];
    if (pTempArray == NULL)
    {
        return false;
    }
    mergesort(a, 0, n-1, pTempArray);
    delete[] pTempArray;
    return true;
}
void mergesort(int a[], int first, int last, int temp[])
{
    if (first < last)
    {
        int mid =(first + last)/ 2;
        mergesort(a, first, mid, temp);
        mergesort(a, mid + 1, last, temp);
        mergesortarray(a, first, mid, last, temp);
    }
}
void mergesortarray(int a[], int first, int mid, int last, int temp[])
{
    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++];
        }
    }
    while (i<= m)
    {
        temp[k++] = a[i++];
    }
    while (j<= n)
    {
        temp[k++] = a[j++];
    }
    for (i = 0; i < k;i++)
    {
        a[first + i] = temp[i];
    }
}
/*
 *         快排 = 挖坑填数加分治法
 **/
//调整数组使  x 左面的值都小于x, 右面的值都大于x;
int AdjustArray(int s[], int l, int r)//返回调整后基准数的位置;
{
    int i = 1,j = r;
    int x = s[l];  //s[1] 就是基准数
    while (i<j)
    { 
        //从右向左找小于x的数来放到s【i】的位置;
        while (i<j && s[j]>=x)
        {
            j--;
        }
        if (i<j)
        {
            s[i] = s[j];//将s[j]填到s[i]中,把s[j]空出来,接着找数来填补
            i++;
        }
        //从左向右找大于或等于x的数来填s[j];
        while (i<j&&s[i] < x)
        {
            i++;
        }
        if (i<j)
        {
            s[j] = s[i];//将s【i】填到s[j]中, 把s[i]空出来, 接着找数来填补
            j--;
        }
    }
    //退出时,把x填到这个坑中
    s[i] = x;
    return i;
}
void quick_sort1(int s[], int r)
{
    if (1 < r)
    {//先调整数组, 然后分治递归;
        int i = AdjustArray(s, 1, r);
        quick_sort1(s, 1, i-1);
        quick_sort1(s, i + 1, r);
    }
}
/*
 *优化版的快排!
 **/
void quicksort(int s[], int r)
{
    if ( 1< r)
    {
        int i = 1, j = r, x = s[1];
        while (i<j)
        {
            while (i<j && s[j]>=x)
            {
                j--;
            }
            if (i < j)
            {
                s[i++] = s[j];
            }
            while (i<j && s[i] <x)
            {
                i++;
            }
            if ( i< j)
            {
                s[j--] = s[i];
            }
        }
        s[i] = x;
        quicksort(s, 1, i - 1);
        quicksort(s, i + 1, r);
    }
}
/*                                   堆和堆排序
 *二叉堆是完全而出书或者是近似完全二叉树。
 *1、二叉堆满足性质:父节点的键值总是大于等于或者小于等于任何一个子节点的键值;
 *2、每个节点的左子树和右子树都是一个二叉堆。(最大堆或者最小堆)
 **/
/*                                堆的插入
 *每次插入都是将新数据放在数组最后。 可以发现从这个新数据的父结点到根结点
 *必然为一个有序的数列, 现在的任务是将这个新数据插入到这个有序数据中——
 *这就类似于 直接插入排序中将一个数据并入到有序区间中,
 **/
//加入i节点,其父节点为(i-1)/2;
void MinHeapFixup(int a[], int i)
{
    int j, temp;
    j = (i - 1) / 2;// parente node
    temp = a[i];
    while (j>=0 &&i != 0 )
    {
        if (a[j] <= temp)
        {
            break;
        }
        a[i] = a[j]; //把较大的子节点往下移动,替换它的子节点
        i = j;
        j = (i - 1) / 2;
    }
    a[i] = temp;
}
//简化版
void MinHeapFixup(int a[], int i)
{
    for (int j = (i - 1) / 2; (j >= 0 && i != 0) && a[i] > a[j]; i = j;j = (i-1)/2)
    {
        swap(a[i],a[j]);
    }
}
//插入新元素 nNum
void MinHeapAddNumber(int a[], int n, int nNum)
{
    a[n] = nNum;
    //MinHeapAddNumber()
    MinHeapFixup(a, n);
}
/*                          堆的删除
 *堆中每次都只能删除第 0 个数据。为了便于重建堆,实际的操作是将最
 *后一个数据的值赋给根结点,然后再从根结点开始进行一次从上向下的调整。调
 *整时先在左右儿子结点中找最小的, 如果父结点比这个最小的子结点还小说明不
 *需要调整了,反之将父结点和它交换后再考虑后面的结点。相当于从根结点将一
 *个数据的“下沉”过程。
 **/
//从i节点开始调整, n为节点总数 从0开始计算 i节点的子节点为  2*i+1,2*i+1
void MinHeapFixdown(int a[], int i,int n)
{
    int j, temp;
    temp = a[i];
    j = 2 * i + 1;
    while (j < n)
    {
        if (j+1 < n && a[j+1] <a[j])//
        {
            j++;
        }
        if (a[j] >= a[j]) // 在左右孩子中找最小的
        {
            j++;
        }
        if (a[j] >= temp)
        {
            break;
        }
        a[i] = a[j];  //把较小向上移动,替换它的父节点;
        i = j;
        j = 2 * i + 1;
    }
    a[i] = temp;
}
//在最小堆中删除数
void MinHeapDeleteNumber(int a[], int n)
{
    swap(a[0], a[n - 1]);
    MinHeapDeleteNumber(a, 0, n - 1);
}
//建立最小堆 
void MakeMinHeap(int a[], int n)
{
    for (int i = n / 2 - 1; i < i >= 0; i--)
    {
        MinHeapFixdown(a, i, n);
    }
}
/*                      堆排序 
 *思路:堆建好之后堆中第 0 个数据是堆中最小的数据。 取出这个数据再执
 *行下堆的删除操作。这样堆中第 0 个数据又是堆中最小的数据,重复上述步骤直
 *至堆中只有一个数据时就直接取出这个数据。
 *堆也是用数组模拟的,故堆化数组后,第一次将 A[0]与 A[n - 1]交换,再对
 *A[0…n-2]重新恢复堆。第二次将 A[0]与 A[n – 2]交换,再对 A[0…n - 3]重新恢复
 *堆,重复这样的操作直到 A[0]与 A[1]交换。由于每次都是将最小的数据并入到
 *后面的有序区间,故操作完成后整个数组就有序了。类似于直接选择排序
 **/
void MinHeapSort(int a[], int n)
{
    for (int i = n - 1; i >= 1;i--)
    {
        Swap(a[i], a[0]);
        MinHeapFixdown(a, 0, i);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值