10.2.2 其他插入排序

折半插入排序

  • 直接插入排序 算法简单,但仅适合于 待排序记录数量小的情况
    待排序记录的数量 很大时,需要对 直接插入排序方法 做出改进。出发点是减少 比较移动 两个操作的次数。
    在这里插入图片描述

  • 因为查找 下一条待排序记录的插入位置 是在 有序序列区 进行查找的,则可以使用 折半查找 来定位。如此实现的插入排序为 折半插入排序

  • 因此 折半排序的步骤 如下:
    1、折半查找,在有序序列区 中找到 最后一个关键字不小于 R[i].key 的记录
    2、每一趟 插入 一条记录有序序列区 ,i = 2, 3, …, n。实现 整个序列 的排序。

  • 重排记录的代码如下:(之前只是修改 指针 ,现在修改 记录地址

void BiInsertionSort(SqList &L)
{
	for(i=2; i<=L.length; i++)
	{
		L.r[0] = r[i]; // 暂存,哨兵
		// 折半查找寻找插入位置
		low = 1;
		high = i-1;
		while(low <= high)
		{
			m = (low+high) / 2;
			if(L.r[0].key < L.r[m].key)
			{
				high = m-1; //插入点在低半区
			}
			else
			{
				low = m+1; // 插入点在高半区
			}
		}
		//已找到插入位置 (high + 1),开始后移
		for(j=i-1; j>=high+1; j--)
		{
			L.r[j+1] = L.r[j];
		}
		L.r[high+1] = L.r[0];
	}
}
  • 上述算法其实就是两步,比较插入。( 比较 是用来找到 插入 的位置)
    减少了 比较次数比较次数 是 O(nlogn).但没改变 插入次数 ,因此 总的时间复杂度 仍然是 O(n2)。
  • 为了减少 插入次数 ,引入下面的 表插入排序

表插入排序

  • 为了减少 在排序过程中进行的移动记录的操作次数,必须改变 排序过程中采用的存储结构静态链表):
    1、利用 静态链表 进行排序,排序过程中只改变 指针 ,不改变 记录位置
    2、排序完成之后,一次性地调整各个记录相互之间的位置,即将每个记录都调整到它们所应该在的位置上。

  • 下面的算法是第二步的实现

#define SIZE 100 // 静态链表容量
typedef struct
{
	RcdType rc; // 记录项
	int next; // 指针项
} SLNode;
typedef struct
{
	SLNode r[SIZE]; // 0号单元作为表头结点
	int length; // 链表的当前长度
} SLinkListType; // 静态链表类型

void Arrange(SLinkListType &SL)
{
	//根据静态链表SL中各结点的指针值调整记录位置,使得SL中记录按关键字
	//非递减有序顺序排列
	p = SL.r[0].next; // p 指示第一个记录的当前位置
	for(i=1; i<SL.length; i++)
	{
		while(p < i)
		{
			// 此时数组中所有小于i的分量都已经“到位”了
			p = SL.r[p].next;
		}
		q = SL.r[p].next;
		if(q != i)
		{
			SL.r[p] <-- --> SL.r[i]; //连个记录交换,赋值次数是3,减少了记录移动的次数
			SL.r[i].next = p;
		}
		p = q;
	}
}
  • 移动记录的次数 减少了,最坏的情况是 n-1 次交换,也就是 3 * ( n-1 ) 次记录移动。
    比较记录的次数 没变,
    所以 时间复杂度 仍然是 O( n2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值