c++把各种数据结构的排序算法的课本代码给实现了一下,需要者自取

#include<iostream>
using namespace std;
//总览:时间复杂度O(n2)------起泡排序,直接插入排序,简单选择排序
//O(nlog2n~n2)-----希尔排序
//O(nlog2n)-----快速排序,堆排序和归并排序
//O(n)计数排序,桶排序和基数排序

//最快的是快速排序,虽然时间复杂度不是最小的,但是实践中往往是快速排序最快

//冒泡排序
void BubbleSort(int r[], int n)
{
    int pos = n;
    while (pos!=0)
    {
        int bound = pos;
        //pos与bound的联动很巧妙地使得一旦不执行for中地语句就会中断while循环
        //这里有问题,第一轮不动,是否意味着它就真的不用动了呢,不能记录头交换点,因为不交换不代表
        //就已经可以不考虑了,这个最大值那一头不一样
        pos = 0;
        for (int i=1; i < bound; i++)
        {
            if (r[i] > r[i + 1])
            {
                r[0] = r[i];//r[0]用于暂存元素
                r[i] = r[i + 1];
                r[i + 1] = r[0];
                pos = i;//存储末尾最后一次交换的位置
            }
        }

        
    }
}
//直接插入排序
//思想很简单,就是每次往后找一个元素插入到前段有序的序列中
//至于有序序列如何构建,开始的时候仅一个元素肯定是有序的,然后
//就是一个已经构建好的有序序列,然后后续的插入操作总可以维持一个
//有序序列前段然后就可以了
void InserSort(int r[], int n)
{
    for (int i = 2; i <= n; i++)//从第二个开始,因为第一个视为自动有序
    {
        if (r[i] < r[i - 1])//如果i比i-1还大,那就不要移动,只有小于时才有操作空间
        {
            r[0] = r[i];//r[0]用作暂存元素i
            r[i] = r[i - 1];//i的位置存i-1(因为i-1比i大)
            int j = i - 2;
            for (; r[0] < r[j]; j--)//注意r[0]是暂存元素不是最小元素
            
                r[j + 1] = r[j];//如果当前查找的元素比存的元素i大则让当前元素赋给其下一个元素
            //同时由于已经提前把i-1个这个最大元素存到了i中,i-1相当于空位,原i的值的0位置处
            //然后借助空位不断把比r[0]大的元素都往后移
            r[j + 1] = r[0];//如果r[j]<r[0]则则r[j]<r[0]<r[j+1],本次的j+1是上次的j,所以j+1是空位,所以赋值 
            
        }//书本代码有问题,自己分析,j的作用域出问题了
    }
}
//简单选择排序
void SelectSort(int r[], int n)
{
    for (int i = 1; i < n; i++)
    {
        int index = i;
        for (int j = i + 1; j <= n; j++)
            if (r[i] < r[index])
                index = j;//找最小的位置,从i开始
        if (index != i)
        {
            r[0] = r[i];
            r[i] = r[index];
            r[index] = r[0];//让其与r[i]换值,以r[0]为中间值
        }
    }
}
//希尔排序
void ShellInsert(int r[], int n)
{
    for (int d = n / 2; d >= 1; d = d / 2)
    {
        //间隔长度从n/2每次都除以2
        for (int i = d + 1; i <= n; i++)
        {
            //从第二个d长度的序列开始一次与前一个序列比较
            //这个操作很聪明,通过第二个序列开始往前比较,一定不会出现指针超限,因为d最大是n/2,
            //我往前面找,哪怕是第一个也是d+1,最后一个就更不必说了
            if (r[i] < r[i - d])
            {
                r[0] = r[i];
                int j = i - d;
                for (; j > 0 && r[0] < r[j]; j = j - d)
                    r[j + d] = r[j];
                r[j + d] = r[0];//这里出现了类似的错误,自己后面排查一下------还是j的作用域错误
                //然后对所有序列对应的各组的相同相对位置的所有元素进行直接插入排序
            }
        }
    }
}
//快速排序
int Partion(int r[], int first, int end)
{
    int i = first;
    int j = end;
    int pivot = r[i];//通过pivot,i,j三个变量可以确定新的一趟
    while (i < j)
    {
        while ((i < j) && (r[j] >= pivot))
            j--;//含义不断减小j的同时直到找到比pivot小的j
        r[i] = r[j];//然后赋值给i,因为i的值已经存给i[0]了
        while ((i < j) && (r[i] <= pivot))
            i++;//不断增大j的同时直到找到比pivot大的,
        r[j] = r[i];//然后赋值给j,因为j的值已经存到原来i的位置了,接下来可以重复,因为这时候i的值也被存了
    }
    r[i] = pivot;
    return i;//其结果就是实现了一趟的快速排序
}
void Qsort(int r[], int i, int j)
{
    if (i < j)
    {
        int pivotloc = Partion(r, i, j);//Partion函数返回相等时的i---亦是j,其两端再进行新的趟
        Qsort(r, i, pivotloc - 1);//左半边同样操作
        Qsort(r, pivotloc + 1, j);//右半边同样操作,其中i,j取决于如果没有被pivotloc覆盖就是1,n-1,但是大多数
        //都会被覆盖
    }
}
//堆排序
void Sift(int r[], int k, int m)
{
    //这是筛选算法,数据类型是二叉树的顺序表
    //其作用只是筛选它和它的孩子是否满足堆(父母节点都大于孩子节点或者都小于)
    int i = k, j = 2 * i;
    while (j <= m)
    {
        if (j < m && r[i] < r[j + 1])j++;
        if (r[i] > r[j])break;
        else
        {
            int m = 0;
            m = r[i];
            r[i] = r[j];
            r[j] = m;
            i = j;
            j = 2 * i;
        }
    }
}
void HeapSort(int r[], int n)
{
    for (int i = n / 2; i >= 1; i--)
        Sift(r, i, n);//首先从n/2开始依次往前筛选,因为这些节点才有孩子
    //这之后你的顺序表已经符合了堆二叉树,但是顺序表还不是有序的
    //接下来我们要利用对二叉树根节点最大或者最小的特性
    for (int i = n; i > 1; i--)
    {
        r[0] = r[1]; r[1] = r[i]; r[1] = r[0];
        Sift(r, 1, i - 1);
        //这时候每次拿走根节点的头元素,存到对应位置(肯定是无序列的最后一个),同时把对应位置的值赋给头节点
        //然后使得序列长度-1,对根节点进行筛选,恢复为有序堆二叉树,然后再输出(输出,赋值,拿出)根节点以此类推
    }
}
//归并排序
void Merge(int r[], int r1[], int s, int m, int t)
{
    //归并算法
    int i = s;
    int j = m + 1;
    int k = s;//确定两个需要被归并的序列,都是r的部分,并且赋值到r1中
    while (i <= m && j <= t)
    {
        if (r[i] <= r[j])
            r1[k++] = r[i++];
        else
            r1[k++] = r[j++];//由于i,j本身有序,依次比较,谁满足谁赋值谁加1
    }
    while (i <= m)
    {
        r1[k++] = r[i++];//如果一方没了,为了防止指针域超限,单拿出来考虑
    }
    while (j <= t)
        r1[k++] = r[j++];//同上
}
void MergePass(int r[], int r1[], int n, int h)
{
    int i = 1;
    while (i <= n - 2 * h + 1)
    {//至少右两个子序列,那就一直+2h直到不够
        Merge(r, r1, i, i + h - 1, i + 2 * h - 1);
        i += 2 * h;
    }
    if (i < n - h + 1)
        //如果这样说明有一个不够,那就照样合并,只是上边while的后半句不符合了,所以单拎出来
        Merge(r, r1, i, i + h - 1, n);
    else
        for (; i <= n; i++)
            r1[i] = r[i];//如果只剩一个了,那么就直接视为已经合并了,新子序列为原序列
}

void MergeSort(int r[], int r1[], int n)
{
    int h = 1;
    while (h < n)
    {//依次堆长度为2的n次方的长度的序列进行归并
        MergePass(r, r1, n, h);
        h = 2 * h;//将r1归并到r中
        MergePass(r1, r, n, h);
        h = h * 2;//将r归并到r1中,同一循环的两次h不一样,但是不影响,最后都会到r1中
        //而且最后一次,如果再前面一个merge pass中先满足了h的条件也不影响,无非是对一个h长度远大于
        //n的一次归并,那在上面MergePass算法里不就是不够一个h的情况吗,直接不变即可
    }
}
//void MergeSort(int r[], int r1[], int s,int t)
//{
//    int r2[100];
//    if (s == t)r1[s] = r[s];//只有一个元素,就直接赋值
//    else
//    {
//        int m = (s + t) / 2;//否则找到序列长度的一半
//        MergeSort(r, r2, s, m);//将由分好序列内部进行归并
//        MergeSort(r, r2, m + 1, t);
//        Merge(r2, r1, s, m, t);//堆分好的序列之间进行归并
//    }
//}

int main()
{
    int a[10];
    a[0] = 0;
    for (int i = 1; i < 10; i++)
    {
        cin >> a[i];
    }
    BubbleSort(a, 9);
    for (int i = 1; i < 10; i++)
    {
        cout << a[i] << endl;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值