第6章 常用算法与数据结构副本.docx

上传人:b****5 文档编号:6362670 上传时间:2023-01-05 格式:DOCX 页数:33 大小:304.12KB
下载 相关 举报
第6章 常用算法与数据结构副本.docx_第1页
第1页 / 共33页
第6章 常用算法与数据结构副本.docx_第2页
第2页 / 共33页
第6章 常用算法与数据结构副本.docx_第3页
第3页 / 共33页
第6章 常用算法与数据结构副本.docx_第4页
第4页 / 共33页
第6章 常用算法与数据结构副本.docx_第5页
第5页 / 共33页
点击查看更多>>
下载资源
资源描述

第6章 常用算法与数据结构副本.docx

《第6章 常用算法与数据结构副本.docx》由会员分享,可在线阅读,更多相关《第6章 常用算法与数据结构副本.docx(33页珍藏版)》请在冰豆网上搜索。

第6章 常用算法与数据结构副本.docx

第6章常用算法与数据结构副本

第6章

常用算法与数据结构

本章要点:

·排序与查找

·堆栈与队列

·树

在非数值计算应用中,计算机加工的数据对象往往是大量的数据。

这些数据存取、查找、插入和删除等等操作效率的提高,仅仅依赖程序设计的技巧已经无法达到目的,必须对这些被加工数据的组织形式加以研究,找出最佳的数据组织形式,并与好的程序设计技巧相配合,才能达到提高效率的目的。

算法(algorithm)就是非空的、有限的指令序列,遵循它就可以完成某一确定的任务。

数据结构是研究计算机中大量数据存储的组织形式,并定义相应的运算以提高计算机的数据处理的能力。

在编制程序程序之前,首先应该选择一个恰当的数据结构和一个好的算法。

6.1排序与查找

本节介绍一些编程中常用的基本算法,这些算法不但在面向过程的程序设计中经常会用到,也是面向对象编程的重要工具之一。

实际上,面向对象的编程中,封装起来的对象之间使用的是面向对象的原则,而被封装的对象内部依然遵循面向过程的编程的原则。

6.1.1排序

排序是计算机中常用的一种重要的运算,其功能是将一个数据序列中的各个数据元素根据某个给出的关键值按从大到小(称为降序)或从小到大(称为升序)的排列。

排序将改变数据序列中各元素的先后顺序,使之成为有序序列。

排序分为内部排序和外部排序,内部排序的方法有很多,这里只介绍冒泡排序、选择排序和插入排序三种常用的排序算法。

1、插入排序

插入排序(InsertionSort)是一种简单的排序方法,它把待排序的数据序列划分成有序子列和无序子列两部分,程序开始时有序子列为空而无序子列包含了全部数据。

它的基本操作是把无序子列的固定位置的数据(例如无序子列最前面的数据)插入到有序子列的合适位置中,从而得到一个新的、长度增1的有序子列。

例如,已知待排序的一组序列的初始排列如下所示:

50,32,63,97,75,13,26,45

假设在排序过程中,前4个数已按递增的次序重新排列,构成一个含4个数的有序序列

{32,50,63,97}

现要将第5个数插入到上述序列,以得到一个新的含5个数的有序序列,则首先要在上述序列中进行查找以确定75所应插入的位置,然后进行插入。

假设从97起向左进行顺序查找,由于63<75<97,则75应插入到63和97之间,从而得到下列新的有序序列

{32,50,63,75,97}

【例6.1】插入排序

/*ProgramnameInsertSortDemo.java

一个插入排序的例子

*/

classArrayIns

{

privatedouble[]a;//定义double类型的数组

privateintnElems;//变量nElems存储数据项数

publicArrayIns(intmax)//构造器

{

a=newdouble[max];

nElems=0;

}

publicvoidinsert(doublevalue)//插入数据到数组中

{

a[nElems]=value;

nElems++;

}

publicvoiddisplay()//显示数组中的数据

{

for(intj=0;j

System.out.print(a[j]+"");

System.out.println("");

}

publicvoidinsertionSort()

{

intin,out;

for(out=1;out

{

doubletemp=a[out];

in=out;

while(in>0&&a[in-1]>=temp)//查找插入的位置

{

a[in]=a[in-1];//数据在数组中右移一个位置

--in;

}

a[in]=temp;//插入到正确位置

}

}//endinsertionSort()

}//endclassArrayIns

classInsertSortDemo{

publicstaticvoidmain(String[]args)

{

intmaxSize=100;//数组初始大小为100

ArrayInsarr;

arr=newArrayIns(maxSize);//建立排序数组

arr.insert(50);//插入8个数

arr.insert(32);

arr.insert(63);

arr.insert(97);

arr.insert(75);

arr.insert(13);

arr.insert(26);

arr.insert(45);

System.out.println("排序前:

");

arr.display();

arr.insertionSort();//进行插入排序

System.out.println("排序后:

");

arr.display();

}//endmain()

}//endclassInsertSortDemo

在main()方法中通过调用方法insert(doublevalue)插入了8个数,然后调用方法insertSort()进行排序,display()方法用来输出数据,其结果输出如图6-1所示。

图6-1【例6.1】的运行结果

2、冒泡排序

冒泡排序(BubbleSort)算法的基本思路是把当前数据序列中的各相邻数据两两比较,发现任何一对数据间不符合要求的升序或降序关系则立即调换它们的顺序,从而保证相邻数据间符合升序或降序的关系。

冒泡排序的过程很简单。

首先将序列中的第一个数和第二个数进行比较,若为逆序(即第一个数>第二个数),则将两个数交换之,然后比较第二个数和第三个数。

依次类推,直至第n-1个数和第n个数进行过比较为止。

上述过程称为第一趟冒泡排序,其结果使得序列中的最大数被安置到最后一个数的位置上。

然后进行第二趟冒泡排序,对前n-1个记录进行相同的操作,其结果是使序列中次大的数被安置到第n-1个数的位置上。

依此类推,每一趟两两比较和交换(称为“扫描”)都将使一个数据就位并使未排序的数据数目减一,所以经过k趟〔1≤k<n〕扫描之后,所有的数据都将就位,未排序数据数目为零,而整个冒泡排序就完成了。

显然,判别冒泡排序结束的条件应该是“在一趟排序过程中没有进行过交换数的操作”。

例如,已知待排序的一组序列的初始排列如下所示:

50,32,63,97,75,13,26,45

则经过第一趟冒泡排序后其序列如下所示:

32,50,63,75,13,26,45,97

【例6.2】冒泡排序

/*ProgramnameBubbleSortDemo.java

一个冒泡排序的例子

*/

classArrayBub

{

privateint[]a;//定义int类型的数组

privateintnElems;//变量nElems存储数据项数

publicArrayBub(intmax)//构造器

{

a=newint[max];

nElems=0;

}

publicvoidinsert(intvalue)//插入数据到数组中

{

a[nElems]=value;

nElems++;//数据项增1

}

publicvoiddisplay()//显示数组中的数据

{

for(intj=0;j

System.out.print(a[j]+"");

System.out.println("");

}

publicvoidbubbleSort()

{

intout,in;

for(out=nElems-1;out>1;out--)

for(in=0;in

if(a[in]>a[in+1])//若第in个数大于第in+1个数,则

swap(in,in+1);//交换这两个数据

}

privatevoidswap(intone,inttwo)

{

doubletemp=a[one];

a[one]=a[two];//实现交换

a[two]=temp;

}

}//endclassArrayBub

classBubbleSortDemo{

publicstaticvoidmain(String[]args)

{

intmaxSize=100;//数组初始大小为100

ArrayBubarr;

arr=newArrayBub(maxSize);//建立排序数组

arr.insert(50);//插入8个数

arr.insert(32);

arr.insert(63);

arr.insert(97);

arr.insert(75);

arr.insert(13);

arr.insert(26);

arr.insert(45);

System.out.println("排序前:

");

arr.display();

arr.bubbleSort();//进行冒泡排序

System.out.println("排序后:

");

arr.display();

}//endmain()

}//endclassBubbleSortDemo

在main()方法中通过调用方法insert(doublevalue)插入了8个数,然后调用方法bubbleSort()进行排序,display()方法用来输出数据,其结果输出如图6-2所示。

图6-2【例6.2】的运行结果

在程序中,swap(intone,inttwo)方法用来交换下标为one与下标为two的两个数的位置,其中用临时变量temp暂存数据。

冒泡排序的一种改进方法是,在排序过程中,记下每次扫描时最后依次交换序列中的数发生的下标,显然,低于此下标的数都已排好了序,因而,扫描在此数位置处终止,而不必进行到预先确定的下限。

3、选择排序

选择排序(SelectSort)的基本思想也是把数据序列划分成两个子序列,一个子序列是已经排好序的数据,另一个子序列中是尚未排序的数据。

程序开始时有序子列为空,而无序子列包含了全体数据。

从无序子列中选择一个合适的数据,例如,选择无序子列中的最小数据放到有序子列中,这样有序子列长度增长一,而无序子列减少一,这就是一次选择过程。

重复这个选择过程,每次都在无序子列剩余的未排序数据中选择最小的一个放在有序子列的尾部,使得有序子列不断增长而无序子列不断减少,最终无序子列减少为空,所有的数据都在有序子列中按要求的顺序排列,整个排序的操作也就完成了。

【例6.3】选择排序

/*ProgramnameSelectSortDemo.java

一个选择排序的例子

*/

classArraySel

{

privatedouble[]a;//定义double类型的数组

privateintnElems;//变量nElems存储数据项数

publicArraySel(intmax)//构造器

{

a=newdouble[max];

nElems=0;

}

publicvoidinsert(doublevalue)//插入数据到数组中

{

a[nElems]=value;

nElems++;//数据项增1

}

publicvoiddisplay()//显示数组中的数据

{

for(intj=0;j

System.out.print(a[j]+"");

System.out.println("");

}

publicvoidselectionSort()

{

intout,in,min;

for(out=0;out

{

min=out;//选择最小数

for(in=out+1;in

if(a[in]

min=in;//则得到一个更小的数

swap(out,min);//且交换之

}//endfor(outer)

}//endselectionSort()

privatevoidswap(intone,inttwo)

{

doubletemp=a[one];

a[one]=a[two];//实现交换

a[two]=temp;

}

}//endclassArraySel

classSelectSortDemo{

publicstaticvoidmain(String[]args)

{

intmaxSize=100;//数组初始大小为100

ArraySelarr;

arr=newArraySel(maxSize);;//建立排序数组

arr.insert(50);//插入8个数

arr.insert(32);

arr.insert(63);

arr.insert(97);

arr.insert(75);

arr.insert(13);

arr.insert(26);

arr.insert(45);

System.out.println("排序前:

");

arr.display();

arr.selectionSort();//进行冒泡排序

System.out.println("排序后:

");

arr.display();

}//endmain()

}//endclassSelectSortDemo

在main()方法中通过调用方法insert(doublevalue)插入了8个数,然后调用方法selectionSort()进行排序,display()方法用来输出数据,其结果输出如图6-3所示。

图6-3【例6.3】的运行结果

上面介绍的几种排序算法各有特点,其中插入排序最简单,当序列中的数“基本有序”或n值较小时,它是最佳的排序方法,因此长将它和其它的排序方法结合在一起使用。

冒泡排序适合于排序数据数目不是很多的情况,但是它的操作代价较高,如果有N个数据参加排序,则使用冒泡算法的运算次数是N3数量级的量;选择排序和插入排序两个算法的代价比冒泡算法低一个数量级,运算次数在N2数量级。

除了上述讲的三种方法外,还有其它许多种排序方法,例如快速排序、归并排序、堆排序等。

6.1.2查找

查找(Searching)是根据给定的某个值,在一个数据集合或数据序列中确定一个其关键字等于给定值的数据元素。

若数据集合或数据序列中存在这样的一个数据元素,则称查找是成功的,此时查找的结果为给出整个数据元素的信息,或指示该数据元素在数据集合或数据序列中的位置;若数据集合或数据序列中不存在关键字等于给定值的数据元素,则称查找不成功。

例如,表6-1为某学生自然班情况,学生的学号为关键字。

假设给定值为20020115,则通过查找可得该学生的姓名、性别等,此时查找是成功的。

若给定值为20020136,则由于表中没有关键字为20020136的记录,则查找不成功。

表6-1学生自然班情况

学号

姓名

性别

籍贯

其它

20020115

李明

北京

20020116

刘丽

江西

由于查找需要处理大量的数据,所以查找过程可能会占用较多的系统时间和系统内存;为了提高查找操作的效率,需要精心设计查找算法来降低执行查找操作的时间和空间代价。

较常用的查找算法有顺序查找、折半查找等。

1、顺序查找

顺序查找(SequentialSearch)是最简单的查找算法,它的查找过程为:

从数据序列的第一个数据开始,若某个关键字和给定值比较相等,则查找成功;反之,若直至最后一个数据,其关键字和给定值比较都不等,则表明数据序列中没有所查关键字,查找不成功。

顺序查找对于数据序列没有特殊的要求,这个序列可以是排好序的,也可以是未排好序的,对于查找操作都没有影响。

在数据序列中数据数目不多时,使用顺序查找非常方便。

当然,顺序查找也可以从数据序列的最后一个数据开始。

【例6.4】顺序查找

/*ProgramnameSqSearch.java

一个顺序查找的例子

*/

publicclassSqSearch{

//数据数组

publicstaticint[]data={50,32,63,97,75,13,26,45};

publicstaticvoidmain(String[]args)

{if(sequence(63))//查找63

System.out.println("Thedata63found.");

else

System.out.println("Thedata63nofound!

");

if(sequence(25))//查找25

System.out.println("Thedata25found.");

else

System.out.println("Thedata25nofound!

");

}

publicstaticbooleansequence(intkey){

inti;//数组下标变量

for(i=0;i<8;i++)

{

System.out.print("["+data[i]+"]");//输出数据

if(key==data[i]){//若查找到数据

System.out.println("");

returntrue;//则返回true

}

}

System.out.println("");

returnfalse;//否则返回false

}

}

输出结果如图6-4所示。

图6-4【例6.4】的运行结果

2、折半查找

如果数据序列中有N个数据,顺序查找的运算次数是N的数量级,如果N很大,使用顺序查找的代价也相应增大;如果希望大幅度降低运算次数,可以考虑使用折半查找算法。

使用折半查找要求数据序列必须是已经排好序(升序、降序均可)的有序序列。

折半查找(BinarySearch)的查找过程是:

先确定待查关键字所在的范围(区间),然后逐步缩小范围直到找到或找不到该关键字为止。

它先让待查关键值与有序序列中间的一个数据比较,并利用这个中间数据把有序序列划分成一前一后两个子列;如果待查关键值大于中间数据,说明序列中如果存在欲查找的数据,那么这个数据必然保存在后一个子列中,因为只有这个子列中的所有数据都大于中间数据;相反,如果待查关键值小于中间数据,说明欲查找的数据存在于前一个子列中。

这样,通过一次比较,把查找的范围缩小了一半,从整个序列变成一个子列。

同理,继续使用对分方法不断划分更小的子列,缩小查找范围,直至目标子列中只剩余了一个数据;如果这个数据与待查关键值相匹配,则查找成功;否则说明原来的整个数据序列中并不存在一个与待查关键值相匹配的数据,查找失败。

例如,已知一组有序序列如下所示:

 

现要查找数据63和25。

假设指针low和high分别指示待查元素所在范围的下界和上界,指针mid指示区间的中间位置,即mid=(low+high)/2,在本例中,low和high的初值分别为0及7,mid=7/2=3(取不大于该数的最大整数)。

查找数据63的过程如下:

步骤1:

63>data[3]=45,则low=mid+1=3+1=4,high=7,mid=(4+7)/2=5。

步骤2:

63=data[5],找到数据。

查找数据25的过程如下:

步骤1:

25

步骤2:

25

步骤3:

25>data[0],则low=mid+1=0+1=1,high=0,因为low>high,所以未能找到数据。

【例6.5】折半查找

/*ProgramnameBSearch.java

一个折半查找的例子

*/

publicclassBSearch{

publicstaticintmax=8;

publicstaticint[]data={13,26,32,45,50,63,75,97};

publicstaticintcounter=1;//计算查找的次数的变量

publicstaticvoidmain(String[]args)

{

for(inti=0;i<8;i++)

System.out.print("["+data[i]+"]");//输出数据

System.out.println("");//换行

if(BinarySearch(63))//查找63

System.out.println("Searchtime="+counter);

else

System.out.println("Thedata63nofound!

");

if(BinarySearch(25))//查找25

System.out.println("Searchtime="+counter);

else

System.out.println("Thedata25nofound!

");

}

publicstaticbooleanBinarySearch(intkey){

intlow;//下界

inthigh;//上界

intmid;//中间位置

low=0;

high=max-1;

while(low<=high)

{

mid=(low+high)/2;

if(key

high=mid-1;//查找前半段

elseif(key>data[mid])//待查找值较大

low=mid+1;//查找后半段

elseif(key==data[mid]){//查找到数据

System.out.println("data["+mid+"]="+data[

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1