• 插入排序与希尔排序


    插入排序描述:有一个数组num[n];它有n个元素,假设其中n-1已经排好序了,那么把剩余的那个元素插入到合适的位置即可,这样就完成了排序。根据这个思想,很明显的可以使用递归来完成它。下面是递归版本的代码.

    #include <iostream>
    using namespace std;
    void InsertionSort(int *num, int n);
    int temp;
    int main()
    {
    	int num[10] = { 0,2,4,9,8,5,6,7,3,1};
    	//int num[10] = { 0,1,1,1,1,0,1,1,1,1 };
    	InsertionSort(num, 10);
    	for (int i = 0; i < 10; i++)
    	{
    		cout << num[i] << '	';
    	}
    	cout << endl;
    	system("pause");
    }
    void InsertionSort(int *num, int n)
    {
    	if (1 == n)		//基准条件
    	{
    		return ;
    	}
    	else
    	{
    		int i;
    		InsertionSort(num, n - 1);
    		if (num[n - 1] > num[0])
    		{
    			for (i = n - 2; i >= 0; i--)
    			{
    				if (num[n - 1] > num[i])		//已经排序好的序列中有比第n-1个小的
    				{
    					temp = num[n - 1];
    					for (int j = n - 1; j > i; j--)
    					{
    						num[j] = num[j - 1];
    					}
    					num[i + 1] = temp;
    					break;
    				}
    			}
    		}
    		else	//已经排序好的序列中都比第n-1个大
    		{
    			temp = num[n - 1];
    			for (int i = n - 1; i > 0; i--)
    			{
    				num[i] = num[i - 1];
    			}
    			num[0] = temp;
    		}
    	}
    }

    递归版本的插入排序,这个程序比较复杂,时间复杂度是Ω(n³)的,因为那个双层循环至少迭代n次,并且循环最大是O(n²)。这个递归版本写起来也不好写。因为数组的插入时间复杂度就是O(n)。如果将数组改成链表,那么数组的插入这个操作的时间复杂度将会降低为O(1)。那么采用循环实现的插入排序的时间复杂度就会降低为O(n²)。

    void InsertionSort1(int *num, int n)		//循环方式
    {
    	int temp;
    	int j;
    	for (int i = 0; i < n - 1; i++)
    	{
    		temp = num[i + 1];
    		for (j = i + 1; j > 0; j--)
    		{
    			if (temp > num[j - 1])         
    			{
                    //如果当前要插入的元素大于等于序列中的某个元素大,那么插入该位置
    				num[j] = temp;
    				break;
    			}
    			else          //把小于要插入元素的值向后移动一个位置,为插入工作做准备。
    			{
    				num[j] = num[j - 1];
    			}
    		}
    	}
    }

    很明显,循环实现的代码时间复杂度只有O(n²)。

    基于限位器版本的插入排序,它省略了j > 0的这个判断操作。限位器加在了序列的最前面。在这里就是num[0]。这个限位器保证了它不会超出数组的范围。

    void InsertionSort2(int *num, int n)
    {
    	int temp;
    	int j;
    	for (int i = 1; i < n; i++)
    	{
    		temp = num[i + 1];
    		num[0] = temp;					 //限位器
    		for (j = i + 1;; j--)            //省略了j > 0这个判断
    		{
    			if (temp >= num[j - 1])		//直接接在后面
    			{
    				num[j] = temp;
    				break;
    			}
    			else						//把数组里面的数据向后移动一个位置。
    			{
    				num[j] = num[j - 1];
    			}
    		}
    	}
    }

    插入排序在输入的数组是严格降序的情况下,(因为此处排序算法是按照升序排列的)该算法出现最坏情况。但是时间复杂度仍然维持在O(n²)。但是该算法对于基本按照升序排列的输入数据有着优秀的表现。(刚好和快速排序相反)这个优点使得它领先于同样时间复杂度的选择排序和冒泡排序。

    值得一提的是,上面插入的过程中,可以将顺序查找改为二分查找,但是这个改动仅对链表有效,对于数组而言,没有用,因为即使找到位置变快了,但是移动的次数并不会减少。所以说算法和数据结构是息息相关的。数据结构设计的好,算法的效率也会得到提高。

    基于插入排序,Shell发明了希尔排序,希尔排序使用一个增量序列h1,h2,...,ht。要求这个序列中h1必须等于1.在使用hk的一趟排序之后,对于每一个i有num[i] <= num[i + hk]成立。所有相隔hk的元素都被排序。Shell本人给出的增量序列是ht = n/2和hk = h(k+1)/2.(k,t是下标).根据这个策略实现的代码如下。

    #include "pch.h"
    #include <iostream>
    using namespace std;
    
    void ShellSort(int *num, int size);
    int main()
    {
    	int num[10] = { 0,2,4,9,8,5,6,7,3,1 };
    	ShellSort(num, 10);
    	for (int i = 0; i < 10; i++)
    	{
    		cout << num[i] << '	';
    	}
    	cout << endl;
    	system("pause");
    }
    
    void ShellSort(int * num, int size)
    {
    	int i, j, increasement;
    	int temp;
    	for ( increasement = size / 2; increasement > 0; increasement /= 2)
    	{
    		for (i = increasement; i < size; i++)
    		{
    			temp = num[i];
    			for ( j = i; j >= increasement; j -= increasement)
    			{
    				if (temp < num[j - increasement])
    				{
    					num[j] = num[j - increasement];
    				}
    				else
    				{
    					break;
    				}
    			}
    			num[j] = temp;
    		}
    	}
    }

    但是这个增量序列并不是足够好。它的最坏情况是退化为插入排序。因此增量问题在于增量序列未必是互为质数。希尔排序看起来比较简单。但是它的时间复杂度的分析时非常困难的。最坏情况下希尔排序为θ(n²)。

    但是希尔排序的实际性能是可以接受的,即使面对很大的数据也是如此。在希尔排序中,增量序列的设计是困难的,它的好坏决定了希尔排序的快慢。(因为它的运行时间依赖于增量序列的选择)

     

  • 相关阅读:
    CSS Grid 布局
    sublime text 3配置c/c++编译环境
    [工具/PC]计算机中丢失libiconv-2.dll,丢失libintl-8.dll,无法定位程序输入点libiconv于动态链接库libiconv-2.dll上问题解决方法
    操作系统Unix、Windows、Mac OS、Linux的故事
    编译型语言与解释型语言的区别及各自的优缺点
    node版本控制之nvm
    Webpack devServer中的 proxy 实现跨域
    webpack-dev-server配置指南(使用webpack3.0)
    [bzoj3295][Cqoi2011]动态逆序对_主席树
    [bzoj2989]数列_KD-Tree_旋转坐标系
  • 原文地址:https://www.cnblogs.com/zy666/p/10504298.html
Copyright © 2020-2023  润新知