挑战408——数据结构(9)——插入排序算法

还有几种排序算法,也表现出跟选择排序算法一样的算法复杂度O(N^2)。我们现在分析其中的一种,称为插入排序算法

插入排序算法

插入排序的操作很简单,跟选择排序一样,它需要遍历所有的元素。但是与选择排序不同,选择排序是找到最小的数,然后与剩下的第一个数交换位置。而插入排序则是遍历所有元素,然后将剩余的元素逐个按顺序插入到已经排好序的vector中
再次考虑我们之前排序示例中使用的数据,下面图解插入排序的算法:

  1. 插入排序算法的第一个循环不需要工作,因为一个元素的vector总是视为被排好了序:
    在这里插入图片描述
  2. 在下一个循环中,你需要将25放在正确的位置,因为56这个序列相当于是排好了序的,所以往这个序列里面插,得到下图:
    在这里插入图片描述
  3. 在第三个循环,需要找到值37应该放哪里,前面的 25 56序列已经排好了,现在要将37插入进去。为了做到这一点,我们需要向前遍历之前排好序的元素。当我们插入元素的时候,需要把每一个较大的元素一个位置向右移动,为要插入的数值腾出空间。 在本例中,56被向后移动了一个位置,37上升到在下标为1的地方。因此,第三个循环后的配置如下所示得到下图:
    在这里插入图片描述
  4. 重复1-3步骤,当遍历完这个vector的时候,vector的顺序就算是排好了。

我们可以看到,在每个循环之后,vector的初始部分总是被排好序,这就意味着以这种方式循环遍历所有位置就等于对整个vector进行排序。
插入排序算法在实践中有广泛的应用,因为如果vector已经以正确的顺序或者已经或多或少地排好序,则它通常在线性时间运行(因为此时只是相当于遍历)。因此,我们通常使用插入排序将只有少数元素并未被排序的的大型vector中。这样耗时是最少的

插入排序的C++代码

#include 
#include 
using namespace std;
/*函数原型*/
void sort(vector<int> & vec);
/*主函数*/
int main() {
	vector<int> vec;
	for (int i = 0; i < 8; i++) {
		int n;
		cin >> n;
		vec.push_back(n);
	}
	sort(vec);
	for (int k = 0; k < vec.size(); k++) {
		cout << vec[k] << " ";
	}
	return 0;
}

void sort(vector<int> &vec) {

	for (int j = 1; j < vec.size(); j++) {
		int i = j - 1;//记录前一位的下标
		int key = vec[j];//记录该位置的值,这个位置之前的数字都已经被排序好
						 //满足条件之后,往后挪动为插入腾出空间 
		while (i >= 0 && key < vec[i]) {   //由于下面用的是I++ 所以应该>=.
				vec[i+1] = vec[i];
				i--;
				vec[i+1] = key;
		}
	}
}

运行结果如下:
挑战408——数据结构(9)——插入排序算法_第1张图片
现在我们可以来回答提出的两个问题了,最好的情况是什么呢?当然是已经排好序的时候啦。因为我们的操作是遍历,然后比较大小再进行插入操作的。如果所有的数据都是后一位大于前一位,那么说明的就是while循环根本都不用执行,因此我们所做的也就仅仅是遍历的过程,也就是线性的复杂度O(N)。
现在我们再讨论一下最坏的情况,是排序一组毫无规则的vector吗?很明显不是的,因为再没有规则它前面都可以有比它小或者大的数,意味着它不用进行所有的插入操作了。最坏的情况我想应该就是让你去用插入排序去将一组降序排列的vector变为升序排序的vector了吧,就像 :
8 7 6 5 4 3 2 1
用插入排序排成:
1 2 3 4 5 6 7 8
每个操作都要移动N-1次。那么我们进行了N次,所以显然跟选择排序的s算法复杂度一样为O(N^2) 。

你可能感兴趣的:(计算机理论基础)