数据结构——排序

所谓排序就是要整理表中的元素, 使之按照关键字递增或递减有序排列。

排序的稳定性

如果关键字相同的两个元素,在排序后的相对位置不发生改变那么就称这个这个排序的算法是稳定的,反之则不稳定。

目录:

1. 插入排序
2. 交换排序
3. 选择排序
4. 归并排序
5. 基数排序

直接插入排序

此算法的思路就是,每次从数组中拿出一个数,然后和前一个数比较,如果符合大于关系则继续遍历,如果小于,那么就循环找到这个数的位置后再插入到数组当中。

可以参考动态变换
那么就可以得到代码

void Insertsort(int R[], int n)
{
	int i, j;
	int temp;
	for (int i = 1; i < n; ++i)
	{
		if(R[i] < R[i - 1]) //不满足要求的顺序
		{
			temp = R[i];//将该数拿出来
			j = i - 1;
			do{R[j + 1] = R[j];j--;}while(j >= 0 && R[j] > temp);//找到这个数的位置
			R[j + 1] = temp;//赋值完成排序
		}
	}
}

时间复杂度 最好:O(n) || 最坏:O( n 2 n^2 n2)
所以期望的时间复杂度就是:O( n 2 n^2 n2)

折半插入排序

为了优化其中的找到这个不满足排序的数的位置,引入二分的算法来找到这个数的位置后集中移动并完成当前数的排序

代码如下

void BinInsertSort(int R[], int len)
{
    int temp, l, r, mid;
	for (int i = 1; i < len; ++i)
    {
        if(R[i] < R[i - 1]) {
            tenp = R[i];
            l = 0, r = i - 1;
            while(l <= r) {
                mid = l + (r - l) / 2;
                if(R[mid] > temp) r = mid - 1;
                else l = mid + 1;
            }

            for (j = i - 1; j >= r + 1; j--)
                R[j + 1] = R[j];
            R[r + 1] = temp;
        }
    }
}

时间复杂度:O( n 2 n^2 n2)

希尔排序

希尔排序是将待排序的数组元素 按下标的一定增量分组 ,分成多个子序列,然后对各个子序列进行直接插入排序算法排序;然后依次缩减增量再进行排序,直到增量为1时,进行最后一次直接插入排序,排序结束。
在这里插入图片描述
代码如下:

template<typename T>
void shell_sort(T array[], int length) {
    int h = 1;
    while (h < length / 3) {
        h = 3 * h + 1;
    }
    while (h >= 1) {
        for (int i = h; i < length; i++) {
            for (int j = i; j >= h && array[j] < array[j - h]; j -= h) {
                std::swap(array[j], array[j - h]);
            }
        }
        h = h / 3;
    }
}

时间复杂度:O( n 2 n^2 n2)

冒泡排序

算法思路:外层套一个循环,然后在循环内一次比较相邻的两个数,如果逆序则调换俩个数的顺序
如果最小的数在这个数组的最后面,我们调用这个算法的话,这个最小的数机会从最后面移到最前面,因此这就是一个冒泡的过程

代码如下:

template<typename T> //整数或浮点数皆可使用,若要使用类(class)或结构体(struct)时必须重载大于(>)运算符
void bubble_sort(T arr[], int len) {
        int i, j;
        for (i = 0; i < len - 1; i++)
                for (j = 0; j < len - 1 - i; j++)
                        if (arr[j] > arr[j + 1])
                                swap(arr[j], arr[j + 1]);
}
快速排序

该方法的基本思想是:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。

代码如下:

void quick_sort(int s[], int l, int r)
{
    if (l < r)
    {
        //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
        int i = l, j = r, x = s[l];
        while (i < j)
        {
            while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
                j--;  
            if(i < j) 
                s[i++] = s[j];
            
            while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
                i++;  
            if(i < j) 
                s[j--] = s[i];
        }
        s[i] = x;
        quick_sort(s, l, i - 1); // 递归调用 
        quick_sort(s, i + 1, r);
    }
}

时间复杂度:O(nlogn)

简单选择排序

算法步骤:
1.在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
2.从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕。

template<typename T> //整數或浮點數皆可使用,若要使用物件(class)時必須設定大於(>)的運算子功能
void selection_sort(std::vector<T>& arr) {
		using namespace std;
        for (int i = 0; i < arr.size() - 1; i++) {
                int min = i;
                for (int j = i + 1; j < arr.size(); j++)
                        if (arr[j] < arr[min])
                                min = j;
                swap(arr[i], arr[min]);
        }
}

时间复杂度:O( n 2 n^2 n2)

归并排序

算法思路:

1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
2.设定两个指针,最初位置分别为两个已经排序序列的起始位置;
3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
4.重复步骤 3 直到某一指针达到序列尾;
5.将另一序列剩下的所有元素直接复制到合并序列尾。

template<typename T> // 整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)的運算子功能
void merge_sort(T arr[], int len) {
    T *a = arr;
    T *b = new T[len];
    for (int seg = 1; seg < len; seg += seg) {
        for (int start = 0; start < len; start += seg + seg) {
            int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
            int k = low;
            int start1 = low, end1 = mid;
            int start2 = mid, end2 = high;
            while (start1 < end1 && start2 < end2)
                b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
            while (start1 < end1)
                b[k++] = a[start1++];
            while (start2 < end2)
                b[k++] = a[start2++];
        }
        T *temp = a;
        a = b;
        b = temp;
    }
    if (a != arr) {
        for (int i = 0; i < len; i++)
            b[i] = a[i];
        b = a;
    }
    delete[] b;
}

时间复杂度:O(nlogn)

基数排序

算法思路就是:
将每个整数按照每一位进行比较

int maxbit(int data[], int n) //辅助函数,求数据的最大位数
{
   int maxData = data[0];              ///< 最大数
   /// 先求出最大数,再求其位数,这样有原先依次每个数判断其位数,稍微优化点。
   for (int i = 1; i < n; ++i)
   {
       if (maxData < data[i])
           maxData = data[i];
   }
   int d = 1;
   int p = 10;
   while (maxData >= p)
   {
       //p *= 10; // Maybe overflow
       maxData /= 10;
       ++d;
   }
   return d;
/*    int d = 1; //保存最大的位数
   int p = 10;
   for(int i = 0; i < n; ++i)
   {
       while(data[i] >= p)
       {
           p *= 10;
           ++d;
       }
   }
   return d;*/
}
void radixsort(int data[], int n) //基数排序
{
   int d = maxbit(data, n);
   int *tmp = new int[n];
   int *count = new int[10]; //计数器
   int i, j, k;
   int radix = 1;
   for(i = 1; i <= d; i++) //进行d次排序
   {
       for(j = 0; j < 10; j++)
           count[j] = 0; //每次分配前清空计数器
       for(j = 0; j < n; j++)
       {
           k = (data[j] / radix) % 10; //统计每个桶中的记录数
           count[k]++;
       }
       for(j = 1; j < 10; j++)
           count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
       for(j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
       {
           k = (data[j] / radix) % 10;
           tmp[count[k] - 1] = data[j];
           count[k]--;
       }
       for(j = 0; j < n; j++) //将临时数组的内容复制到data中
           data[j] = tmp[j];
       radix = radix * 10;
   }
   delete []tmp;
   delete []count;
}

时间复杂度:O(d(n +r))

感谢你的阅读 :)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

He_xj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值