活动地址:CSDN21天学习挑战赛
正文
-
梗:
希尔排序这个名字,来源于它的发明者希尔,也称作“缩小增量排序”,是插入排序的一种更高效的改进版本。 -
At first,我们先look一张我从某文章*的表格,来了解一下这几大算法
-
图都看了,那我也不得不提一嘴,图里面的东西了
-
算法效率
在一个算法设计完成后,还需要对算法的执行情况做一个评估。一个好的算法,可以大幅度的节省运行的资源消耗和时间。在进行评估时不需要太具体,毕竟数据量是不确定的,通常是以数据量为基准来确定一个量级,通常会使用到时间复杂度和空间复杂度这两个概念。 -
时间复杂度
通常把算法中的基本操作重复执行的频度称为算法的时间复杂度。算法中的基本操作一般是指算法中最深层循环内的语句(赋值、判断、四则运算等基础操作)。我们可以把时问频度记为T(n),它与算法中语句的执行次数成正比。其中的n被称为问题的规模,大多数情况下为输入的数据量。对于每一段代码,都可以转化为常数或与n相关的函数表达式,记做f(n)。如果我们把每一段代码的花费的时间加起来就能够得到一个刻画时间复杂度的表达式,在合并后保留量级最大的部分即可确定时间复杂度,记做O(f(n)),其中的O就是代表数量级。
常见的时间复杂度有(由低到高): O(1)、O(log2 n)、O(n)、O(n log2n)、O(n2)、o(n3)、O(2")、O(nl)。 -
空间复杂度
程序从开始执行到结束所需要的内存容量,也就是整个过程中最大需要占用多少的空间。为了评估算法本身,输入数据所占用的空间不会考虑,通常更关注算法运行时需要额外定义多少临时变量或多少存储结构。如:如果需要借助一个临时变量来进行两个元素的交换,则空间复杂度为O(1).
-
时间复杂度与空间复杂度的分类
时间复杂度
-
最坏的情况
最坏的情况莫过于,完整的遍历了整个集合,也没有找到需要找的的元素,循环执行次数与n相关,所以时间复杂度为O(n). -
最好的情况
第一次循环便找到了元素,则时间复杂度为常数级O(1); -
平常的情况
综合两种情况,顺序查找的时间复杂度为O(n),属于查找较慢的算法。
空间复杂度
算法不会改变原有的元素集合,只需要一个额外的变量控制索引变化,所以空间复杂度为常数级:O(1)。
希尔排序
两个49在排序前后位置颠倒了,所以希尔排序是不稳定的
- 我们知道,插入排序对于大规模的乱序数组的时候效率是比较慢的,因为它每次只能将数据移动一位,希尔排序为了加快插入的速度,让数据移动的时候可以实现跳跃移动,节省了一部分的时间开支。
实行过程图解:
void print(int a[], int n,int cases, vector<int>& v)
{
switch (cases)
{
case 1:
for (int j = 0; j < n; j++)
{
cout << a[j] << " ";
}
cout << endl;
break;
case 2:
for (int i = 0; i <= v.size() - 1; i++) {
cout << v.at(i) << " ";
}
break;
default:
printf("cases error");
break;
}
}
void shellSort(int a[], int n) //a -- 待排序的数组, n -- 数组的长度
{
int i, j, gap; // gap为步长,每次减为原来的一半。
for (gap = n / 2; gap > 0; gap /= 2)
{
// 共gap个组,对每一组都执行直接插入排序
for (i = 0; i < gap; i++)
{
for (j = i + gap; j < n; j += gap)
{
// 如果a[j] < a[j-gap],则寻找a[j]位置,并将后面数据的位置都后移。
if (a[j] < a[j - gap])
{
int tmp = a[j];
int k = j - gap;
while (k >= 0 && a[k] > tmp)
{
a[k + gap] = a[k];
k -= gap;
}
a[k + gap] = tmp;
}
}
}
}
}
全部源代码
#include <vector>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <algorithm>
using namespace std;
vector <int> v{2,223,34,4,4,45,4,66,5768,9,9,9};
int a[20] = { 6,10,14,3,16,11,12,15,5,20,9,13,7,18,17,1,8,2,19,4 };
//生成打乱的数据
void randperm(int Num)
{
srand((int)time(0));
vector<int> temp;
for (int i = 0; i < Num; ++i)
{
temp.push_back(i + 1);
}
random_shuffle(temp.begin(), temp.end());
for (int i = 0; i < temp.size(); i++)
{
cout << temp[i] << ",";
}
getchar();
}
void print(int a[], int n,int cases, vector<int>& v)
{
switch (cases)
{
case 1:
for (int j = 0; j < n; j++)
{
cout << a[j] << " ";
}
cout << endl;
break;
case 2:
for (int i = 0; i <= v.size() - 1; i++) {
cout << v.at(i) << " ";
}
break;
default:
printf("cases error");
break;
}
}
void shellSort(int a[], int n) //a -- 待排序的数组, n -- 数组的长度
{
int i, j, gap; // gap为步长,每次减为原来的一半。
for (gap = n / 2; gap > 0; gap /= 2)
{
// 共gap个组,对每一组都执行直接插入排序
for (i = 0; i < gap; i++)
{
for (j = i + gap; j < n; j += gap)
{
// 如果a[j] < a[j-gap],则寻找a[j]位置,并将后面数据的位置都后移。
if (a[j] < a[j - gap])
{
int tmp = a[j];
int k = j - gap;
while (k >= 0 && a[k] > tmp)
{
a[k + gap] = a[k];
k -= gap;
}
a[k + gap] = tmp;
}
}
}
}
}
int main()
{
//randperm(20);
//print(a,20,1,v);
cout << "初始序列:"<< endl;
print(a, 20,1,v);
shellSort(a, 20);
cout << "排序结果:"<< endl;
print(a, 20,1, v);
getchar();
return 0;
}