链式存储--有头节点--直接插入排序(重点学会分析问题的过程,王红梅抽象分级教学法例子)

void zhijiecharusort(LinkList& l)//直接插入排序
{// 使用指针p先保存下L中未排序元素(无序区中)的信息
	 使用指针p先保存下L中未排序元素(无序区中)的信息
	LinkList p = l->next->next;//第一个节点有序
	l->next->next = NULL;
	// 由于为了构造有序区,已经将待排序元素的第一个元素放在有序区中了,

	// 所以从第二个元素开始遍历,也就是p = L->next->next。 
	while (p)//p指向无序区
	{
		// 每循环一次p后移一位,直至p == NULL.
	// 进行插入有序区的操作时会改变p->next的值所以需要选保存一下
		LinkList q = p->next;
		// 为方便比较,用一个指针pre,指向有序区。(重点)
		LinkList pre = l;//为什么不能等于l->next
			// 遍历有序区中的所有元素,直至有序区末尾或者找到:
	// p所指的元素 大于 pre的next所指的元素为止,
		while (pre->next != NULL && pre->next->data < p->data)//pre->next->data < p->data一旦不符合这个条件就成:pre->data < p->data&&pre->next->data > p->data
			pre = pre->next;                                  //pre->next == NULL跳出循环,即pre是有序区最后一个节点

		// 找到比p大的节点后,执行插入操作,因为插入操作需要用到
	// 被插入节点的前驱节点,所以在比较时,用了pre->next来和p比较
		p->next = pre->next;
		pre->next = p;
		// 用q把p的值恢复过来,使得循环继续指向无序区的下一个节点
		p = q;//往后移动1位因为:LinkList q = p->next;
	}
}
直接插入排序就是:
先从待排序的元素中取出第一个元素。
取出的这个第一个元素当作有序区的第一个元素。
接着从待排序的元素中取出第二个元素。
然后将第二个元素插入到有序区中的合适位置,也就是,将第二个元素与第一个元素比较,谁小谁就排在有序区的前面。
接着,在待排序的元素中取第三个元素,然后再在有序区中比较,直至取遍所有待排序的元素。
例题
有一个带头节点的单链表 L (至少有一个数据节点),设计一个算法使其元素递增有序排列。

在算法讲授的过程中,以问题为研究对象,按照提出问题,分析问题,解决问题,总结问题的求解过程。例如:在将冒泡排序算法时,(1)用一个形象的图示介绍冒泡排序的基本思想;(2)提出问题,要完成冒泡排序需要解决哪些关键问题,这 是问题分解思想,问题分解体现开放性思维(3)引导学生通过排序过程的分析应该如何解决这些关键问题,这实际贯彻了一种抽象分级的思想(4)最后把这些问题连在一起,完成冒泡排序算法的设计。

分析

使用直接插入排序算法进行排序。

  • 首先,我们需要构造出一个有序区,也就是构造一个存放有序区的列表。
  • // 使用原链表L构造了一个有序区,有序区中只有一个元素,
    // 这个元素是链表L的开始节点(头节点之后的那个节点)
    L->next->next = NULL;
    

  • 但是,发现将原链表L构造成有序区后发现,原链表的信息丢失了(开始节点之后的节点都没有了,变成了NULL),所以,在构造有序区之前需要保存下开始节点之后的信息。
// 使用指针p先保存下L中未排序元素(无序区中)的信息
p = L->next->next;
// 使用原链表L构造了一个有序区,有序区中只有一个元素,
// 这个元素是链表L的开始节点(头节点之后的那个节点)
L->next->next = NULL;

  • 接下来的任务就是遍历无序区中的元素,将它们一个一个的取出来。
  • // 使用指针p先保存下L中未排序元素(无序区中)的信息
    p = L->next->next;
    // 使用原链表L构造了一个有序区,有序区中只有一个元素,
    // 这个元素是链表L的开始节点(头节点之后的那个节点)
    L->next->next = NULL;
    // 由于为了构造有序区,已经将待排序元素的第一个元素放在有序区中了,
    // 所以从第二个元素开始遍历,也就是p = L->next->next。 
    while(p != NULL){
    	p = p->next; // 每循环一次p后移一位,直至p == NULL.
    }
    

  • 每次从无序区中取一个元素后,接着应该将其和有序区中元素进行比较。
  • // 使用指针p先保存下L中未排序元素(无序区中)的信息
    p = L->next->next;
    // 使用原链表L构造了一个有序区,有序区中只有一个元素,
    // 这个元素是链表L的开始节点(头节点之后的那个节点)
    L->next->next = NULL;
    // 由于为了构造有序区,已经将待排序元素的第一个元素放在有序区中了,
    // 所以从第二个元素开始遍历,也就是p = L->next->next。 
    while(p != NULL){
    	// 为方便比较,用一个指针pre,指向有序区。
    	pre = L;  
    	// 遍历有序区中的所有元素,直至有序区末尾或者找到:
    	// p所指的元素 大于 pre的next所指的元素为止,
    	while(pre->next != NULL && pre->next->data < p->data)
    		pre = pre->next;
    	p = p->next; // 每循环一次p后移一位,直至p == NULL.
    }
    

  • 经过比较过后,可以知道无序区中的第一个元素在有序区中的位置,接下来将其插入有序区中。
  • // 使用指针p先保存下L中未排序元素(无序区中)的信息
    p = L->next->next;
    // 使用原链表L构造了一个有序区,有序区中只有一个元素,
    // 这个元素是链表L的开始节点(头节点之后的那个节点)
    L->next->next = NULL;
    // 由于为了构造有序区,已经将待排序元素的第一个元素放在有序区中了,
    // 所以从第二个元素开始遍历,也就是p = L->next->next。 
    while(p != NULL){
    	// 每循环一次p后移一位,直至p == NULL.
    	// 进行插入有序区的操作时会改变p->next的值所以需要选保存一下
    	q = p->next; 
    	// 为方便比较,用一个指针pre,指向有序区。
    	pre = L;  
    	// 遍历有序区中的所有元素,直至有序区末尾或者找到:
    	// p所指的元素 大于 pre的next所指的元素为止,
    	while(pre->next != NULL && pre->next->data < p->data)
    		pre = pre->next;
    	// 找到比p大的节点后,执行插入操作,因为插入操作需要用到
    	// 被插入节点的前驱节点,所以在比较时,用了pre->next来和p比较
    	p->next = pre->next;
    	pre->next = p;
    	// 用q把p的值恢复过来,使得循环继续指向无序区的下一个节点
    	p = q;  
    }
    

  • 在算法讲授的过程中,以问题为研究对象,按照提出问题,分析问题,解决问题,总结问题的求解过程。例如:在将冒泡排序算法时,(1)用一个形象的图示介绍冒泡排序的基本思想;(2)提出问题,要完成冒泡排序需要解决哪些关键问题,这 是问题分解思想,问题分解体现开放性思维(3)引导学生通过排序过程的分析应该如何解决这些关键问题,这实际贯彻了一种抽象分级的思想(4)最后把这些问题连在一起,完成冒泡排序算法的设计。。。。。更重要:算法设计完成后,要及时进行梳理,重新厘清思路,就像过河一样,别人给河里放了几块垫脚石,我们过了河之后,要回过头来看看垫脚石是否舒服,学习人家怎么做的,以后遇到类似情况我们是否也能做这样的工作,这样才能培养学生的算法设计能力。

  • 完整的代码

  • void sort(LinkList * &L){
    	LinkList *p,*pre,*q;
    	p = L->next->next;		// 先保存下L的第二个元素,因为下一步要将L变成只有一个元素的有序表。  
    	L->next->next = NULL;	// 将L变成只有一个元素的有序表
    	// 从L的第二个元素开始遍历整个L直至表尾 
    	while(p != NULL){
    		q = p->next;
    		pre = L;	// 先用pre来保存L。
    		while(pre->next !=NULL && pre->next->data < p->data) // 遍历pre所指向的有序表L,直至找到比p大的节点 
    			pre = pre->next; 
    		p->next = pre->next;
    		pre->next = p;
    		p = q;	
    	} 
    }
    

    王红梅:数据结构从概念到c++----教师用书:0.2.4算法的抽象分级(page6)

  • 在算法讲授的过程中,以问题为研究对象,按照提出问题,分析问题,解决问题,总结问题的求解过程。例如:在将冒泡排序算法时,(1)用一个形象的图示介绍冒泡排序的基本思想;(2)提出问题,要完成冒泡排序需要解决哪些关键问题,这 是问题分解思想,问题分解体现开放性思维(3)引导学生通过排序过程的分析应该如何解决这些关键问题,这实际贯彻了一种抽象分级的思想(4)最后把这些问题连在一起,完成冒泡排序算法的设计。。。。。。更重要:算法设计完成后,要及时进行梳理,重新厘清思路,就像过河一样,别人给河里放了几块垫脚石,我们过了河之后,要回过头来看看垫脚石是否舒服,学习人家怎么做的,以后遇到类似情况我们是否也能做这样的工作,这样才能培养学生的算法设计能力。

  • 在形式化思维方法 方面,通过描述算法的过程向学生展示设计算法的思路和方法,建立抽象化的思想并掌握相关技术,培养抽象分级的意识和能力。按照上述问题求解的过程,找到每个关键问题的解决方法后,不要急着用描述算法的语言(如c++)描述算法,而是采用::图示理解问题及求解思想------伪代码描述-----c++描述---的3级模式描述算法一方面培养抽象分级的能力;一方面锻炼伪代码描述算法的能力,这两种能力往往学生是欠缺的。

  • 采用抽象分级讲授算法,通过讲过程讲思路讲方法培养学生的逻辑思维能力和开放式思维能力。在解决问题的过程中学会将问题拆开,将一个大问题拆成几个这问题来思考,将一个子问题拆成几个抽象的逻辑步骤来解决。

  • 首先学会分析问题,从问题给定的条件(输入)出发,找到思考问题的入口点,从入口出发寻找解决问题的途径,不断提出子问题,解决子问题直到解决本原问题或分析问题,从问题的结论(输出)出发,思考为得到这个结论应该解决哪些具体问题,不断提出子问题,解决子问题直到解决本原问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值