算法详解.docx

上传人:b****2 文档编号:3251059 上传时间:2023-05-05 格式:DOCX 页数:21 大小:24.62KB
下载 相关 举报
算法详解.docx_第1页
第1页 / 共21页
算法详解.docx_第2页
第2页 / 共21页
算法详解.docx_第3页
第3页 / 共21页
算法详解.docx_第4页
第4页 / 共21页
算法详解.docx_第5页
第5页 / 共21页
算法详解.docx_第6页
第6页 / 共21页
算法详解.docx_第7页
第7页 / 共21页
算法详解.docx_第8页
第8页 / 共21页
算法详解.docx_第9页
第9页 / 共21页
算法详解.docx_第10页
第10页 / 共21页
算法详解.docx_第11页
第11页 / 共21页
算法详解.docx_第12页
第12页 / 共21页
算法详解.docx_第13页
第13页 / 共21页
算法详解.docx_第14页
第14页 / 共21页
算法详解.docx_第15页
第15页 / 共21页
算法详解.docx_第16页
第16页 / 共21页
算法详解.docx_第17页
第17页 / 共21页
算法详解.docx_第18页
第18页 / 共21页
算法详解.docx_第19页
第19页 / 共21页
算法详解.docx_第20页
第20页 / 共21页
亲,该文档总共21页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

算法详解.docx

《算法详解.docx》由会员分享,可在线阅读,更多相关《算法详解.docx(21页珍藏版)》请在冰点文库上搜索。

算法详解.docx

算法详解

折半查找

      又称二分查找。

  使用条件:

有序集合。

     算法思想:

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

  关键点在于比较中间位置所记录的关键字和给定值的比较,如果比给定值大(这里假设集合从小到大排列)那么可以缩小区间范围(集合开始-->中间位置的上一位),在比较该区间的中间位置所记录的关键字与给定值,依次循环到找到或者找不到位置。

     举例编程:

这里有一个整数数据inta[10]={1,5,10,13,17,23,65,77,81,93};

  

(1)这是递归(感谢园友zdd指出这里判断条件的错误,应该改为if(min>max)

//折半查找

//数组必须按照一定的顺序

//参数:

最大,最小,目标(参数类型为整数)

int BinarySearch(int min,int max,int num)

{

if(min==max)return -1;

int mid=(min+max)/2;

if(a[mid]==num)return mid;

else if(a[mid]

{

return BinarySearch(mid+1,max,num);

}

else

{

return BinarySearch(min,mid-1,num);

}

}

     

(2)非递归

//非递归算法

int BinarySearch_F(int num)

{

int min=0;

int max=9;

int mid;

while(min<=max)

{

mid=(min+max)/2;

if(a[mid]==num)return mid;

else if(a[mid]>num)max=mid-1;

else min=mid+1;

}

return -1;

}

  性能分析:

时间复杂度O(logn)

   插入排序

  使用条件:

可对比大小的集合。

  算法思想:

将一个记录插入到已排好序的有序列中,从而得到一个新的,记录数增1的有序序列。

待插记录依次比较已经排好序列,如果序列数大于该待插记录,那么该序列往后挪一位,直到找到序列小于待插记录,那么此时插入到该序列的后一个位置,依次上面操作,直至插完位置。

  举例编程:

intb[10]={77,1,65,13,81,93,10,5,23,17}将其排序

//插入排序

//这里temp是哨兵位

//从小到大

void InsertSort()

{

int temp;

int j;

for(int i=1;i<10;i++)

{

temp=b[i];

for(j=i-1;j>=0;j--)

{

if(b[j]>temp)

{

b[j+1]=b[j];

}

else

{

break;

}

}

b[j+1]=temp;

}

cout<<"thesortis:

";

for(int i=0;i<10;i++)

{

cout<

}

cout<

}

    性能分析:

时间复杂度O(n^2)

索引查找

索引查找是在索引表和主表(即线性表的索引存储结构)上进行的查找。

索引查找的过程是:

1)  首先根据给定的索引值K1,在索引表上查找出索引值等于KI的索引项,以确定对应予表在主表中的开始位置和长度,

2) 然后再根据给定的关键字K2,茬对应的子表中查找出关键字等于K2的元素(结点)。

对索引表或子表进行查找时,若表是顺序存储的有序表,则既可进行顺序查找,也可进行二分查找,否则只能进行顺序查找。

一提到“索引”,估计大家第一反应就是“数据库索引”,对的,其实主键建立“索引”,就是方便我们在海量数据中查找。

 实现索引查找时常使用的三个术语:

1) 主表:

这个很简单,要查找的对象。

2)  索引项:

一般我们会用函数将一个主表划分成几个子表,每个子表建立一个索引,这个索引叫做索引项。

3) 索引表:

索引项的集合也就是索引表。

一般“索引项”包含三种内容:

index,start ,lemgth 

 第一:

 index,也就是索引指向主表的关键字。

第二:

start,也就是index在主表中的位置。

第三:

length, 也就是子表的区间长度。

 代码实现:

[java] viewplaincopy

1.public class IndexSearch {  

2.  

3.    // 主表  

4.    static int[] students = { 101, 102, 103, 104, 105, 0, 0, 0, 0, 0, 201, 202,  

5.            203, 204, 0, 0, 0, 0, 0, 0, 301, 302, 303, 0, 0, 0, 0, 0, 0, 0 };  

6.    // 索引表  

7.    static IndexItem[] indexItem = { new IndexItem(1, 0, 5),  

8.            new IndexItem(2, 10, 4), new IndexItem(3, 20, 3), };  

9.  

10.    // 查找数据  

11.    public static int indexSearch(int key) {  

12.        IndexItem item = null;  

13.  

14.        // 建立索引规则  

15.        int index = key / 100;  

16.  

17.        // 首先去索引找  

18.        for (int i = 0; i < indexItem.length; i++) {  

19.            if (indexItem[i].index == index) {  

20.                item = new IndexItem(index, indexItem[i].start,  

21.                        indexItem[i].length);  

22.                break;  

23.            }  

24.        }  

25.  

26.        // 如果item为null,则说明在索引中查找失败  

27.        if (item == null)  

28.            return -1;  

29.  

30.        for (int i = item.start; i < item.start + item.length; i++) {  

31.            if (students[i] == key) {  

32.                return i;  

33.            }  

34.        }  

35.        return -1;  

36.    }  

37.  

38.    // / 插入数据  

39.    public static int insert(int key) {  

40.        IndexItem item = null;  

41.        // 建立索引规则  

42.        int index = key / 100;  

43.        int i = 0;  

44.        for (i = 0; i < indexItem.length; i++) {  

45.            // 获取到了索引  

46.            if (indexItem[i].index == index) {  

47.                item = new IndexItem(index, indexItem[i].start,  

48.                        indexItem[i].length);  

49.                break;  

50.            }  

51.        }  

52.        if (item == null)  

53.            return -1;  

54.        // 更新主表  

55.        students[item.start + item.length] = key;  

56.        // 更新索引表  

57.        indexItem[i].length++;  

58.        return 1;  

59.    }  

60.  

61.    public static void main(String[] args) {  

62.        int value = 205;  

63.        // 将205插入集合中,过索引  

64.        int index = insert(value);  

65.        insert(308);  

66.  

67.        // 如果插入成功,获取205元素所在的位置  

68.        if (index == 1) {  

69.            System.out.println("\n插入后数据:

" + Arrays.toString(students));  

70.            System.out.println("\n数据元素:

205在数组中的位置为 " + indexSearch(205) + "位");  

71.        }  

72.  

73.    }  

74.  

75.}  

76.  

77.// 索引项实体  

78.class IndexItem {  

79.    // 对应主表的值  

80.    public int index;  

81.    // 主表记录区间段的开始位置  

82.    public int start;  

83.    // 主表记录区间段的长度  

84.    public int length;  

85.  

86.    public IndexItem() {  

87.    }  

88.  

89.    public IndexItem(int index, int start, int length) {  

90.        this.index = index;  

91.        this.start = start;  

92.        this.length = length;  

93.    }  

94.}  

95.  

96.运行结果:

  

97.原数据为:

[101, 102, 103, 104, 105, 0, 0, 0, 0, 0, 201, 202, 203, 204, 0, 0, 0, 0, 0, 0, 301, 302, 303, 0, 0, 0, 0, 0, 0, 0]  

98.  

99.插入后数据:

[101, 102, 103, 104, 105, 0, 0, 0, 0, 0, 201, 202, 203, 204, 205, 0, 0, 0, 0, 0, 301, 302, 303, 308, 0, 0, 0, 0, 0, 0]  

100.  

101.数据元素:

205在数组中的位置为 14位 

 插入排序(InsertionSort)的基本思想是:

每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子文件中的适当位置,直到全部记录插入完成为止。

    本节介绍两种插入排序方法:

直接插入排序和希尔排序。

直接插入排序基本思想

1.直接插入排序的基本思想 

直接插入排序(StraightInsertionSorting)的基本思想是:

把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。

把a[i]插入到a[0],a[1],...,a[i-1]之中的具体实施过程为:

先把a[i]赋值给变量t,然后将t依次与a[i-1],a[i-2],...进行比较,将比t大的元素右移一个位置,直到发现某个j(0<=j<=i-1),使得a[j]<=t或j为(-1),把t赋值给a[j+1].

2、第i-1趟直接插入排序:

    通常将一个记录R[i](i=2,3,…,n-1)插入到当前的有序区,使得插入后仍保证该区间里的记录是按关键字有序的操作称第i-1趟直接插入排序。

    排序过程的某一中间时刻,R被划分成两个子区间R[1..i-1](已排好序的有序区)和R[i..n](当前未排序的部分,可称无序区)。

    直接插入排序的基本操作是将当前无序区的第1个记录R[i]插人到有序区R[1..i-1]中适当的位置上,使R[1..i]变为新的有序区。

因为这种方法每次使有序区增加1个记录,通常称增量法。

    插入排序与打扑克时整理手上的牌非常类似。

摸来的第1张牌无须整理,此后每次从桌上的牌(无序区)中摸最上面的1张并插入左手的牌(有序区)中正确的位置上。

为了找到这个正确的位置,须自左向右(或自右向左)将摸来的牌与左手中已有的牌逐一比较。

一趟直接插入排序方法

1.简单方法

    首先在当前有序区R[1..i-1]中查找R[i]的正确插入位置k(1≤k≤i-1);然后将R[k..i-1]中的记录均后移一个位置,腾出k位置上的空间插入R[i]。

  注意:

    若R[i]的关键字大于等于R[1..i-1]中所有记录的关键字,则R[i]就是插入原位置。

2.改进的方法

  一种查找比较操作和记录移动操作交替地进行的方法。

具体做法:

    将待插入记录R[i]的关键字从右向左依次与有序区中记录R[j](j=i-1,i-2,…,1)的关键字进行比较:

    ①若R[j]的关键字大于R[i]的关键字,则将R[j]后移一个位置;

      ②若R[j]的关键字小于或等于R[i]的关键字,则查找过程结束,j+1即为R[i]的插入位置。

    关键字比R[i]的关键字大的记录均已后移,所以j+1的位置已经腾空,只要将R[i]直接插入此位置即可完成一趟直接插入排序。

直接插入排序算法

1.算法描述

 实现程序

voidinsert_sort(ElemTypea[],intn)

//待排序元素用一个数组a表示,数组有n个元素

{inti,j;

ElemTypet; 

for(i=1;i

{t=a[i];//把待排序元素赋给t

j=i-1; 

while((j>=0)&&(t

{a[j+1]=a[j];j--;}//顺序比较和移动

a[j+1]=t;}

}

4、直接插入排序的效率分析

(1)时间复杂度

从时间分析,首先外层循环要进行n-1次插入,每次插入最少比较一次(正序),移动两次;最多比较i次,移动i+2次(逆序)(i=1,2,…,n-1)。

若分别用Cmin,Cmax和Cave表示元素的总比较次数的最小值、最大值和平均值,用Mmin,Mmax和Mave表示元素的总移动次数的最小值、最大值和平均值,则上述直接插入算法对应的这些量为:

Cmin=n-1Mmin=2(n-1)

Cmax=1+2+…+n-1=(n2-n)/2Mmax=3+4+…+n+1=(n2+3n-4)/2

Cave=(n2+n-2)/4Mmax=(n2+7n-8)/4

因此,直接插入排序的时间复杂度为O(n2)。

由上面对时间复杂度的分析可知,当待排序元素已从小到大排好序(正序)或接近排好序时,所用的比较次数和移动次数较少;当待排序元素已从大到小排好序(逆序)或接近排好序时,所用的比较次数和移动次数较多,所以插入排序更适合于原始数据基本有序(正序)的情况. 

插入法虽然在最坏情况下复杂性为O(n^2),但是对于小规模输入来说,插入排序法是一个快速的排序法。

许多复杂的排序法,在规模较小的情况下,都使用插入排序法来进行排序,比如快速排序。

(2)空间复杂度

首先从空间来看,它只需要一个元素的辅助空间,用于元素的位置交换O

(1)

(3)稳定性:

插入排序是稳定的,因为具有同一值的元素必然插在具有同一值得前一个元素的后面,即相对次序不变.

(4)结构的复杂性及适用情况

插入排序是一种简单的排序方法,他不仅适用于顺序存储结构(数组),而且适用于链接存储结构,不过在链接存储结构上进行直接插入排序时,不用移动元素的位置,而是修改相应的指针。

 

折半插入排序

  使用条件:

可对比大小的集合。

  算法思想:

基本思想与简单插入排序思想相似,唯一的不同点在于找出插入的位置,简单插入排序用的是依次比较,这里折半插入排序改进了,将依次查找改进成折半查找

  举例编程:

intb[10]={77,1,65,13,81,93,10,5,23,17}将其排序

void BinaryInsertSort()

{

int temp,min,max,mid;

int j;

for(int i=1;i<10;i++)

{

min=0;max=i-1;

temp=b[i];

while(min<=max)

{

mid=(min+max)/2;

if(b[mid]>temp)

{

max=mid-1;

}

else

{

min=mid+1;

}

}

for(j=i-1;j>=max+1;j--)

{

b[j+1]=b[j];

}

b[max+1]=temp;

}

cout<<"thesortis:

";

for(int i=0;i<10;i++)

{

cout<

}

cout<

}

  性能分析:

时间复杂度O(n^2)

  虽然这里时间复杂度与简单插入排序一样,但是通过查找找到插入的位置用的比较次数是明显减少的。

冒泡排序

使用条件:

集合的元素可对比大小

算法思想:

连续地扫描待排序的记录,每扫描一次,都会找出最小记录,使之更接近顶部。

由于每次扫描都会把一条记录置于它的最终最正确的位置,因此下次扫描不需要重新检查这条记录

举例编程:

intb[10]={77,1,65,13,81,93,10,5,23,17}将其冒泡排序(这里笔者将概念弄混淆了,感谢zdd的指出)

//冒泡排序

void Bubble(int b[10])

{

int temp;

int i;

for(i=9;i>0;i--)

{

for(int j=0;j

{

if(b[j]>b[j+1])

{

temp=b[j];

               b[j]=b[j+1];

               b[j+1]=temp;

       }

}

}

cout<<"thesortis:

";

for(int i=0;i<10;i++)

{

cout<

}

cout<

}

性能分析:

时间复杂度O(n^2)

希尔排序

使用条件:

集合的元素可对比大小

算法思想:

先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序“时,在对全体记录进行一次直接插入排序。

子序列构成的不是简单“逐段分割”,而是相隔某个“增量”的记录组成一个子序列。

因此比较排序时候关键字较小的记录就不是一步一步往前挪动,而是相隔一定增量移动,该“增量”呈现一个递减趋势,最后这个“增量”总是为1,那么此时序列已基本有序,只要作少量的比较和移动几个完成排序。

希尔排序不好把握增量的设定。

一般8个数我们认为设定“增量”为:

4,2,1。

(这是一般希尔排序的设定)。

那么笔者这里要拟定一个求“增量”的公式h(n+1)=3*h(n)+1,(h>N/9停止)这个公式可能选择增量不是最合适,但是却适用一般“增量”的设定。

如果是8个数的话,那么这里增量就是1。

举例编程:

intb[10]={77,1,65,13,81,93,10,5,23,17}将其希尔排序

//希尔排序自增量需要自己合适选择

void ShellSort(int b[10])

{

int h,i;

int n=10;

//通过这个循环算出增量为1和4

for(h=1;h<=n/9;h=3*h+1);

//增量循环

for(;h>0;h/=3)

{

for(i=h;i

{

int j,temp;

temp=b[i];

//插入排序

for(j=i-h;j>=0;j=j-h)

{

if(b[j]>temp)

{

b[j+h]=b[j];

}

else

{

break;

}

}

b[j+h]=temp;

}

}

cout<<"thesortis:

";

for(int i=0;i<10;i++)

{

cout<

}

cout<

}

性能分析:

时间复杂度对于希尔排序就有点复杂,它根据具体的“增量”不同而不同,这里笔者采用严蔚敏《数据结构》的O(n^3/2)

快速排序

使用条件:

可对比大小的集合。

算法思想:

通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则可分别对这两部分记录继续这种排序,最后达到有序序列。

这里有一个关键点,就是选取分割的“基准”。

肯定是大于这个“基准”分成一个部分,小于这个“基准”分成一个部分。

这里笔者默认取该部分第一个记录为“基准”。

举例编程:

intb[10]={77,1,65,13,81,93,10,5,23,17}

//快速排序

void QuickSort(int *b,int low,int high)

{

//交换函数

void Sawp(int *a,int *b);

int Old_low=low;

int Old_high=high;

while(low

{

while(*(b+high)>*(b+low)&&low

Sawp(b+low,b+high);

while(*(b+low)<*(b+high)&&low

Sawp(b+low,b+high);

}

if(Old_lo

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

当前位置:首页 > 小学教育 > 小学作文

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2