【数据结构算法自学笔记】自学笔记 思路+伪代码 (持续更新)

数据结构算法自学笔记 大话思路与伪代码

以下为笔者自学过程中觉得需要记录的东西,并不代表正确且专业的知识,所以如果大家看到有不对的地方,希望大家能高抬贵手多多指出,谢谢!(持续更新)

一、排序

一)插入排序

插入排序对于少量元素的排序是一个比较有效的算法。

白话思路:对于一个未排列的数组,暂且称当前正在排列移动的数字称作当前数。一般当前数从数组的第二位开始,遵循从当前数的当前位置向前开始比对,例如:a[1]需要和下标为1之前的数字一一比较,即与a[0]进行比较,也就是当前数从右向左依次比较。如果比较过程中,发现比当前数大的比较数,怎么将比较数往后移动一位,同时,该比较数之前的数同意向后移动一位,直到一个比当前数小的数字,将当前数插入到该数字之后的位置上。

伪代码

INSTERTION-SORT(A)	//A为传入的参数 是一个数组
	for j=1 to A.length
		key = A[j]	//将当前待排序的元素备份
		i = j-1		//将下标定位到当前待排序数的前一位
		while(i>0 && A[i]>key)	//当前排序的数字依次与下标之前的元素比较 为的是找到比当前排序数大的元素
			//然后将它们依次后移一位,直到找到比key小的值,停止,退出循环
			A[i+1] = A[i]
			i=i-1
		A[i+1] = key	//将之前备份的元素插入到循环结束处,该数完成比较插入动作

图示
在这里插入图片描述

总结:也就是把当前数抽出,并移动比当前数大的数,最后将当前数插入到循环停止的下标处。

二)归并排序

思路:将一组数据递归分解成足够小的若干组,合并过程中两两比较大小,重新插入到原数组中。归并排序利用到分治法的思想,采取三步骤:分解——将一个数组分解成足够小的若干个小数组;解决——两两数组比较得出有顺序的新数组;合并——将这些排序后的数组,再两两进行比较合并动作,直到最后只有一个数组。
换个说法,分解的意思就是桌上有一副牌,将这副牌从中间分开,分成了两副牌。这两副牌再接着进行相同的操作,即为分解。解决即是A、B两副牌(假定各有两张,且经过前面的操作已分别有序),两副牌都是叠放,牌面朝上。每次将两副牌的最上面一张牌进行比较,较小的一张抽出,抽出牌为新数组,被抽出的一副牌会露出下面的一张新牌,两副牌再进行比较,直到AB两副牌已比较完,得出的新数组即为合并

在这里插入图片描述
分解过程伪代码

MERGE-SORT(A,p,r)	//A为待排序的数组,p为头下标,r为尾下标
	if( p < r)		//为了保证A数组当前p、r头尾下标中间还有数据存在
		q = (p + r)/2	//分割数组,取中间下标
		MERGE-SORT(A,p,q)	//递归调用自身,对上半段元素继续进行相同操作
		MERGE-SORT(A,q+1,r)	//递归调用自身,对下半段元素继续进行相同操作
		MERGE(A,p,q,r)	//当分割到足够小时,进行比较合并操作

解决、合并过程伪代码

MERGE(A,p,q,r)
	n1 = q - p + 1	//计算出目前所需要排序的前半段元素数
	n2 = r -q	//计算出目前所需要排序的后半段元素数
	let L[0,n1] and R[0,n2] be new arrays	//建立两个新数组 用于分别存放前半段和后半段元素
	for i = 0 to (n1-1)
		L[i] = A[p + i]
	for j = 0 to (n2-1) 
		R[j] = A[q + 1 + j]
	L[n1] = R[n2] =//L,R数组的最后一位都存了一个“哨兵位”,目的是为了避免每次抽掉一已比较数字后都
						//要检验一遍数组是否到底,提高了效率,只要指向了哨兵位,说明该数组已检验完
	i = j = 0
	for k = p to r	//循环(r-p+1)次,为的是比较L,R数组(r-p+1)次,然后合并覆盖到数组A中
		if(L[i] <= R[j])
			A[k] = L[i]
			i = i +1
		else
			A[k] = R[j]
			j = j + 1
	// 对于这个“哨兵位”,让我们来做一个假设,L数组的里的数全都比R数组里的数大,所以循环到一半的时候,
	//R数组中的数已经被抽光了,轮到了最后一位为一个非常大的“哨兵位”,那么这个时候L中的元素再去和R数
	//组比较,都是在和这个非常大的“哨兵位”在比较,结果当然是L数组中的元素都比“哨兵位”小,依次合并覆
	//到A数组中,省去了每次都需要检测L、R数组是否到底的步骤,提高效率
补充例题:股票问题(最大子数列)

“一段时间内,股票有涨有降,可以在价格最低的一天买入股票,然后在价格最高的一天卖出股票,以获得最大利润,但是最低价格的一天不一定在最高价格的前面,所以需要求得最高利润的买入股票日和卖出股票日。”

思路:把这段时间的价格换算成价格差来看,即第一天的价格差为第1天和第0天的股票价格差,第2天的价格差为第2天与第1天的股票价格差。此价格差数列必定有正有负,所以得到一组新的数组A。接下来利用分治法的思想:将数组A第一次均分的时候,数组如下被分开成1、2两段(如下图),数组A的任意一个子数组都可能处于任何位置,但总共会有三种情况:
1)整个子数组完全处于1段中;
2)整个子数组完全处于2段中;
3)子数组在1、2都有份,跨越mid。
1)、2)的情况利用递归继续分割,所以现在单独来讨论下第三种情况。
在这里插入图片描述

当单独讨论3)的情况时,他的子数组有一个限制,就是子数组必定经过mid。所以就会有这么个情况:存在A[i ~ mid] 和 A[mid+1 ~ j ]两个子数组,由一个完整的跨越mid的子数组分割而来,所以若干个类似于此的i点和j点,这就变成了左右分别求最大和值最后在合并的计算了,合并即可求出这种情况下的最大子数列。

接下来是这部分伪代码:

FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high)
	left-sum = -//(记录位)建立该比较数的理由在于,从右(mid)向左(low)寻找过程中,sum不断在与左边
					//的数相加,如果加数为负数,则sum变小,left-sum不记录该值;如果加数是正数,而相加后
					//sum超过了left-sum,则记录下该值和当前下标,表示为目前寻找到的最大和。
	sum = 0 //初始值为0 所以第一次比较必定符合判断条件,大于left-sum
	for i = mid downto low
		sum = sum + A[i]
		if sum > left_sum //说明当前遍历的元素符合找到最大和的条件,更新left-sum,并记录下当前元素下标
			left_sum = sum
			max_left = i
	right_sum = -//右边与左边道理相同
	sum = 0
	for j = mid+1 to high
		sum = sum + A[j]
		if sum > right_sum
			right_sum = sum
			max_right = j //记录下right-sum和当前元素的下标
	return (max_left,max_right,left_sum + right_sum) //返回左边、右边达到最大和值要求的下标,合并后
													//的最大值(最大子数列的和)
			

现在来实现求最大子数组问题的分支算法伪代码:

FIND-MAXIMUM-SUBARRAY(A,low,high)
	if high == low	//判断当前子数列是否只有一个元素了
		return (low,high,A[low])
	else //在保证当前子数列内至少有两个元素的情况下
		mid = (low + high)/2
		
		//将当前子数列递归分割 前半段再次进行判断
		(left_low,left_high,left_sum)=FIND-MAXIMUM-SUBARRAY(A,low,mid)
		//判断当前子数列的后半段
		(right_low,right_high,right_sum)=FIND-MAXIMUM-SUBARRAY(A,mid+1,high)
		//判断当前子数列的第3)种情况 计算出最大子数列
		(cross_low,cross_high,cross_sum)=FIND-MAXIMUM-SUBARRAY(A,low,mid,high)
		
		if left_sum >= cross_sum and left_sum >= right_sum
			return (left_low,left_high,left_sum)
		else if right_sum >= left_sum and right_sum >= cross_sum
			return (right_low,right_high,right_sum)
		else return (cross_low,cross_high,cross_sum)

(未完待续)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值