【数据结构】--直接插入排序-解析

直接插入排序

先看排序思路:

直接插入排序是一种最简单的排序方法,它的基本操作是将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表。
来自《数据结构》-----严蔚敏、吴伟民 编著

思路确实很简单,以一个递增的记录序列为例:每每插入一个记录,我们都需将被插入的记录和序列中的每一个记录相比较来确定插入位置,然后插入。仅此而已。但是算法实现的过程很是痛苦。好在书本给出范例供学习参考。
范例中主要有两个困难,一个是查找过程中可能会出现的数组越界问题;另一个是直接在原有有序表上进行排序,而不是搞两个分开的表。我个人认为把两个表分开会更直观一些。不过直观归直观,还是最简洁的算法最有效率。
我将对算法各个过程的理解写到了注释中,加上本人的注释后有些许凌乱,不过个人感觉还是很通俗易懂的。看不懂就说"hhhc"[doge]。算法如下:

 #define MAXSIZE 20
 typedef int KeyType;  //方便起见,将关键字类型设置为整数 
 typedef struct{
  KeyType key;  //关键字项
	 InfoType otherinfo;  //其它数据项 
 }RedType;  //RedType  表示记录类型 
 typedef struct{
  	 RedType r[MAXSIZE+1];  //r[0]闲置,或作为哨兵单元
    int length;  //顺序表长度 
 }SqList;  //SqList 表示顺序表类型

 /*************结构体结束,正事儿开始*************/

 void InsertSort(SqList &L){
 //对顺序表L做直接插入排序
	for(i=2; i<=L.length; ++i){   //i从2开始,是把第一个记录看成已排好的顺序表,从第2个开始向其中插入
		if( LT(L.r[i].key, L.r[i-1].key) ){  //"LT(A,B)"即A<B; 这里需要将r[i]插入
			L.r[0] = L.r[i];  //复制为哨兵,同时也给r[i]备了一下份
    		L.r[i] = L.r[i-1];  //后边记录比前边记录大,就把后边的备份到r[0],再前边的覆盖后边的
			for(j=i-2; LT(L.r[0].key, L.r[j].key) ;--j){
					L.r[j+1] = L.r[j];
				//j从i-2开始,是因为r[i-1]已覆盖了要插入的r[i]的位置
				//从r[i-2]往前走,遇到比r[0](也就是r[i]) 大的,统统往后移动
				//一遇到比它大的或跟它相等的r[j],就退出循环.
			} //for
			//此时r[j+1]已经后移到r[j+2],r[j+1]的位置算是空出来了,这就是插入r[i]的地方	
			L.r[j+1] = L.r[0];  //把r[i]的备份r[0]插入空位,完成排序
		}//if
	}//for
  }//void InsertSort()
 //到算法写完才想到 还有个数组下标越界的问题没考虑,不过没关系。该问题可能会出现在第 2 个 “for循环” 中
 //假如插入的r[i]是目前序列里最小的,那么j就会一直减一直减,总有j减少的0的时候,不过这个时候就会跳出循
 //环了,因为LT(A,B)表示的是 A<B .

不得不说,写出这种东西真是不简单。不过还不算完,还有强化版本…

直接插入排序pro–折半插入排序

直接插入排序算法简便,且容易实现。当待排序记录的数量n很小时,这是一种很小的排序方法。但是通常待排序序列中的记录数量n很大,不宜采用直接插入排序。由此要改进,在其基础上,从减少“比较”和“移动”的次数着眼。

利用折半查找法查找插入坐标的算法如下:

void BInsertSort(SqList& L){
	for(i=2; i<=L.length; ++i){ 
		L.r[0] = L.r[i];
		low = 1;	high = i-1;  //第一个注意点,high的初始位置不再是整个表的末尾
		while(low<=high){
			mid = ( low + high )/2;
			if( LT(L.r[0].key,L.r[m].key) ) high = mid-1;
			else low = mid+1;
		} //while
		for(j=i-2; LT(L.r[0].key,L.r[j]) ;j--)  L.r[j+1] = L.r[j];
		L.r[high+1] = L.r[0];  //插入 ,插入到哪个地方是个难点
	}
}

讲真,有了插入排序算法的基础再看这个算法的话,着实不那么苦难了。不过还是有两点需要关注一下,一个是 high 的初始值,另一个是插入的位置怎么计算。
① high 初始值:
这里遵循直接插入排序的特点,所被插入的序列是由之前插入的记录构成。而且从原记录表中取记录的顺序是从前往后取。因此 high 不能一开始就取到整个序列的最后方。
②插入位置的计算:
折半查找法的各种操作没有改变,这就需要折半查找法的基础了:在折半查找法中,若查找不到记录,则查找区间一定为-1。我们可以举一个例子来帮助我们寻找插入位置:

记录38496597
位置1234

现有一个记录,关键词值为13,经过计算发现high值最后为0,因此,插入位置便是high+1。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值