插入排序对数组中把数组分为已排序和未排序两部分,一般左边为已排序,右边为未排序
然后每次取未排序序列的第一个元素当要插入的元素,然后遍历已排序的序列,
注意得从后往前遍历已排序序列,因为已排序过的序列是有序的,比如我们数组是1,2,3,5,4
此时我们1,2,3,5已经排好序,4是待插入元素,我们只需要找到已排序序列中比待插入元素大的元素才算满足交换的条件,因为已排序好的末尾是最大的,如果末尾最大的都不满足条件,那末尾前面的肯定不满足了,所以应该从末尾向前遍历已排序元素。

一般我们取数组的下边为1的元素为默认的待插入元素
然后下标为1的左边为默认已排序的元素
取i=1,代表要插入元素的值
j = i -1,已排序好的元素末尾索引

下面我们看一下排序时序图

初始数据\[685, 896, 490, 178, 231\]
排序开始

i=1

无需交换,已排好\[685, 896, 490, 178, 231\]

i=2

j=1

tmp=490

交换后的结果\[685, 896, 896, 178, 231\]

j=0

tmp=490

交换后的结果\[685, 685, 896, 178, 231\]

本轮结果\[490, 685, 896, 178, 231\]

i=3

j=2

tmp=178

交换后的结果\[490, 685, 896, 896, 231\]

j=1

tmp=178

交换后的结果\[490, 685, 685, 896, 231\]

j=0

tmp=178

交换后的结果\[490, 490, 685, 896, 231\]

本轮结果\[178, 490, 685, 896, 231\]

i=4

j=3

tmp=231

交换后的结果\[178, 490, 685, 896, 896\]

j=2

tmp=231

交换后的结果\[178, 490, 685, 685, 896\]

j=1

tmp=231

交换后的结果\[178, 490, 490, 685, 896\]

j=0

tmp=231

本轮结果\[178, 231, 490, 685, 896\]

排序结束

耗时3

最终结果\[178, 231, 490, 685, 896\]
var list = List.generate(5, (index){  
  return Random().nextInt(1000);  
});  
int tmp;   
int start = DateTime.now().millisecondsSinceEpoch;  
print('初始数据$list');  
print('排序开始');  
for(int i = 1;i< list.length;i++){  
  print('i=$i');  
  tmp = list[i];  
  int j = i -1;  
  if(list[j] > tmp) {  
  for(; j>=0;j --){  
  print('j=$j');  
  print('tmp=$tmp');  
  if(list[j]> tmp) {  
  list[j + 1] = list[j];  
  print('交换后的结果$list');  
 } else {  
  break;  
 } }  list[j+1] = tmp;  
  print('本轮结果$list');  
 }else {  
  print('无需交换,已排好$list');  
 }  
}  
print('排序结束');  
print('耗时${DateTime.now().millisecondsSinceEpoch-start}');  
print('最终结果$list');

当初始序列为正序时,只需要外循环n-1次,每次进行一次比较,无需移动元素。此时比较次数(C _{min})和移动次数(M_{min})达到最小值。
此时时间复杂度为O(n))。
当初始序列为反序时,需要外循环n-1次,每次排序中待插入的元素都要和[0,i-1]中的i个元素进行比较且要将这i个元素后移i次,加上tmp=arr[i]与arr[j]=temp的两次移动,每趟移动次数为i+2,此时比较次数和移动次数达到最大值。
C_{max} = 1+2+...+(n-1) = n_(n-1)/2=O(n^2))
M_{max} = (1+2)+ (2+2)+.....+(n-1+2)=(n-1)_(n+4)/2=O(n^2))
此时时间复杂度O(n))

参考:插入排序--直接插入排序 iarchitect


fantasy525
586 声望18 粉丝

vue react,flutter,android