1 / 24

第五单元 数组与 指针( I )

第五单元 数组与 指针( I ). 5.7 多级指针与多维数组(补充). 5.8 查找与排序. 变量 ppval. 变量 pval. 变量 val. &pval. &val. 10. 5.7 多级指针与多维数组 (选读). 多级指针的概念: 多级指针变量中存的是另一个指针变量的地址,其说明如下: int val=10; int *pval=&val; int **ppval=&pval; // 是多少级指针就有多少 * 号 cout<< val<< ‘ t ’ << * pval<< ‘ t ’ << ** ppval;

jolie-hall
Download Presentation

第五单元 数组与 指针( I )

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第五单元 数组与指针(I) 5.7 多级指针与多维数组(补充) 5.8 查找与排序

  2. 变量ppval 变量pval 变量val &pval &val 10 5.7 多级指针与多维数组 (选读) 多级指针的概念: 多级指针变量中存的是另一个指针变量的地址,其说明如下: int val=10; int *pval=&val; int **ppval=&pval; //是多少级指针就有多少*号 cout<< val<<‘\t’<< *pval<<‘\t’<< **ppval; 这里val、*pval、**ppval值均为10。 注意*号为间接引用运算符,定义中的*号是指针说明符。

  3. 5.7 一级指针与二维数组 指针与一维数组: 指向一维数组(首元素)的同类型指针与该数组名等效: int a[10], *pa =a;// =&a[0]; 则pa[0] ,就是a[0]; *pa,即a[0]; *(pa+1) 和pa[1] ,都代表a[1]。 即a 与pa 两者等效。

  4. 5.7 一级指针与二维数组 二维数组与一级指针: 二维数组在内存中以一维数组的形式存储,所以可以采用一级指针指向并访问它。如有: int x2d[m][n]={1,2,3,4,…..}; int *pt=&x2d[0][0];//&x2d或&x2d[0],可以?,错,不匹配 如何用pt访问x2d[i][j]? X2d数组对应一维内存的索引为i*n+j。 所以*(pt+i*n+j) 就是x2d[i][j],相等。

  5. 5.7 一级指针与二维数组 【例5.14】用指向二维数组首地址的一级指针访问数组元素。 int main( ){ int a[3][6]={{1,2,3,4,5,6},{7,8,9,10,11,12},{13,14,15,16,17,18}}; int * ptr,i,j; ptr=&a[0][0] ; //不能ptr = a; for(i=0;i<18;i++){ cout<<*(ptr+i)<<'\t'; if(i%6==5) cout<<endl; } return 0;} 启示:可用指向任意维数组首地址的一级指针以及长度信息,将数组完整地传递到函数中,从而实现函数(算法)的通用性。

  6. 5.8查找与排序 (I)(P.196) 查找(search):是最重要的计算应用之一,是在数据集合中寻找满足条件的数据,找到后进一步给出该数据对象的细节信息,在数据库技术中称为检索(retrieval)。不同于枚举查找! 排序(sorting): 要实现查找,首先要对数据排序。查找算法不适用杂乱无章的数据。 例如利用计算机数据库可以快速查找到数据,首先因为其数据有序排列,其次使用了查找算法。 5.8.1 常用查找方法 5.8.2 常用的排序法

  7. 5.8.1 常用查找方法 顺序查找: 从首个元素开始,依据一定原则顺序查找直到找到或查到最后元素为止。 查找是按关键字(key word)进行。可以唯一地把资料区分出来的数据项被称为主关键字。如学生的资料,学号可作为主关键字。 对于数据集合,按照关键字小的往前还是后排列,可分别称为升序排列与降序排列。对于升序排列,可以采用对半查找(binary search)。

  8. mid high 20 21 23 26 29 31 37 39 high low mid low 图6.3 查找成功例 23 成功 low mid high 23 2 5 7 8 9 11 13 17 19 20 21 23 39 26 29 37 31 查找 low 20 21 23 mid high 5.8.1 常用查找方法 对半查找: 首先安排两个变量low和high作为关键词序列的首尾两元素的下标,取mid= (low+ high)/2,如mid位置的元素是所查找的,则结束。如果该元素大了,则取low=mid +1, high不变,继续查找;如果该元素小了,则取 high=mid-1,low不变,继续查找。如果查到low>=high仍未找到,则失败,停止。

  9. mid high mid high mid high 9 图6.4 查找失败例 low mid high 10 2 2 5 5 7 7 8 8 9 9 9 11 11 11 13 13 13 17 17 17 19 29 20 31 21 23 37 26 39 查找 low low low 5.8.1 常用查找方法—对半查找 注意:low=mid+1和high=mid-1非常重要,没有加1和减1时,可能数据存在而找不到。如在图6.3中,如果找到了仅剩20、21、23这一步,这时取low=mid,则剩下21、23,mid = (low + high)/2,得mid = low ,下一步low = mid ,还是剩下21、23,mid 不为23,永远找不到23了。

  10. 5.8.1 常用查找方法 【参见例6.4】对半查找递归算法,升序表采用数组来表示。 递归方法易读易懂,但效率低。注意递归的隐式循环代码编写。 【参见例6.5】对半查找迭代算法。 该例中迭代算法的可读性也不差,效率要高于递归。注意迭代的显式循环代码编写 的关键点。

  11. 参见【例6.4】对半查找递归算法 参见【例6.4】对半查找递归算法,数组表示有序表。 int BinarysearchRec (constint & x, const int *pslst, int low, int high) { // x为定值 int mid=-1; if (low<=high) { mid=(low+high)/2; if (*(pslst+mid)<x) mid = Binarysearch(x,pslst,mid+1,high); //中间点小于定值,查找右区间,注意mid+1 elseif(x<*(pslst+mid)) mid=Binarysearch(x,pslst,low,mid-1); //中间点大于定值,查找左区间,注意 mid-1 } returnmid;//找到返回下标;未找到但结束了,返回mid=-1,不判断 } 递归方法易读易懂,但效率低。

  12. 参见【例6.4】对半查找递归算法 int main() { constint h=20; int i,k=37; int a[h]={0,2,3,5,7,11, 13, 17, 19, 23, 31,34,39, 59,61,67,80,89,99,101}; //升序 int* pa=a; i=BinarysearchRec(k, pa, 0,h-1); cout<<"整数"<<k<<"在表中位置(下标):"<<i<<endl; return 0; }

  13. 5.8.1 常用查找方法 【参见例6.4】对半查找递归算法,升序表采用数组来表示。 递归方法易读易懂,但效率低。注意递归的隐式循环代码编写。 【参见例6.5】对半查找迭代算法。 该例中迭代算法的可读性也不差,效率要高于递归。注意迭代的显式循环代码编写 的关键点。

  14. 参见【例6.5】对半查找迭代算法 参见【例6.5】对半查找迭代算法。 int BinarySearchIt(const int & x, const int *pslst, const int & last) { int high=last, low=0, mid;// last 当前数组的最大下标 if( last == -1 ) return -1;//避免空表出错 while (low<=high ) { mid = (low+high)/2; if ( x<*(pslst+mid) ) high = mid-1; //左缩查找区间 elseif (*(pslst+mid)<x ) low = mid+1; // 右缩查找区间 elsereturn mid; // 找到,就是mid } if(*(pslst+mid) != x ) mid = -1; // 最后还未查找 return mid; } 该例中迭代算法的可读性也不差,效率要高于递归。注意迭代的显式循环代码编写 的关键点。

  15. 5.8.2 常用的排序法 排序的概念: 排序(sorting)是数据处理中经常使用的一种重要运算。用于将数据元素序列由无序调整为有序。 数据元素中一般有多个数据项,排序可选择其中一个可排序的数据项(可进行比较运算)来进行,称为排序关键字。 对高考统计表进行排序,可根据考生的准考证号,它可以保证排序结果的唯一性,称主关键字。 录取时,要按高考总分排序,只可称关键字,这样同一分数的人很多,这些人的排名可再取一个次关键字如数学或语文分来排序,以减少排名相同的几率。 从小到大排序称升序,反之为降序。最常见的排序有插入排序、选择排序和交换排序。

  16. 5.8.2 常用的排序法 1.插入排序(Insert Sorting) (1)直接插入排序的思想是:(以升序为例)当插入第i(i>=1)个元素s[i]时,前面的元素s[0],s[1],…,s[i-1]已经排好序,我们将s[i]的关键字与s[i-1], s[i-2],…,的关键码顺序进行比较,找到第一个比它小的,则s[i]插到该元素之后。 直接插入排序算法中用了一个临时变量temp,要插入的元素放到temp中,这样插入前各元素后移时允许将该元素冲掉。

  17. 5.8.2 常用的排序法 参见【例6.6】升序直接插入排序算法 void InsertSort (const int* pslst, const int &last){ int temp; int i,j; for (i=1;i<=last;i++){ temp=*(pslist+i); j=i; while (j>0&&temp< *(pslist+(j-1))){ *(pslist+j)= *(pslist+(j-1)) ; j--; //查找与移动同时做 } *(pslist+j) =temp; } }

  18. void printArray (constint* pArray, int n) { int i, last=n-1; for(i=0;i<=last;i++){ cout<< *(pArray+i)<<endl; if(i%5==4) cout<<endl; } cout<<endl;} int main(){ const int h=12; int n[h]; int elem[10]={100,89,101,49,0,99,54,22,87,60};//10个 for (int i=0;i<10;i++) n[i]=elem[i];//注:10个元素 int *pa=n; cout<<"未排序表:"<<endl; printArray(pa,10); InsertSort(pa, 9); cout<<"已排序表:"<<endl; printArray(pa,10); return 0;}

  19. 5.8.2 常用的排序法 *(2)对半插入排序(Binary Insert Sort)利用了对半查找的思想。对半插入排序要快于直接插入排序。 【例6.7】升序对半插入排序算法

  20. 【例6.7】升序对半插入排序算法 void BinaryInsertSort(const int* pslst, const int &last){ int temp; int low,high,mid,i,j; for (i=1;i<=last;i++){ temp=*(pslst+i); low=0; high=i-1; while (low<=high){ //请注意与对半查找的不同之处 mid=(low+high)/2; if(temp< *(pslst+mid)) high=mid-1; else low=mid+1; } //稳定排序 for(j=i-1;j>=low;j--) *(pslst+j+1)=*(pslst+j); *(pslst+low)=temp; } } 关键字相同的数据元素,原来在前的排序后仍在前,称稳定排序(同直接插入排序)。

  21. 5.8.2 常用的排序法 2.交换排序 交换排序的基本思想是按关键字两两排序,如果发生逆序则交换之,直到所有的数据都排好为止。 冒泡排序基本思想参见图6.6。最左列为最初的情况,最右列为完成后的情况。首先我们从一列数据底部开始,相邻的两数据进行比较,小的数放上面,一趟比较下来,最小的数据冒到了最上面。再缩小区域,按同样方法继续下一趟交换,如果有一趟比较中没有发生交换,则已排好序。图6.6中,第5列就已排好序,若再继续下一趟就不会发生交换。 图6.6从下往上扫描的冒泡程序

  22. 参见【例6.8】冒泡排序算法 冒泡排序算法。 void BubbleSort(const int* pslst, const int &last){ bool noswap; int i, j, temp; for ( i=0; i<last; i++ ) { //最多做last-1趟 noswap=true; //未交换标志为真 for ( j=last; j>i; j--) { //从下往上冒泡 if ( *(pslst+ j) < *(pslst+ j-1) ) { temp = *(pslst+ j) ; *(pslst+ j) = *(pslst+ j-1); *(pslst+ j-1) = temp; noswap = false; } } if ( noswap ) break; //本趟无交换,则终止算法。 } }

  23. 5.8.2 常用的排序法 3.选择排序(Selection Sort) 基本思想是:每一趟从待排序的记录中选出关键字最小的元素,顺序放在已排好序的子序列的后面,直到全部记录排序完成。直接选择排序(Straight Selection Sort)是最简单方法。 [49 38 65 97 76 13 27 49’]  13 [38 65 97 76 49 27 49’]  13 27 [65 97 76 49 38 49’] 13 27 38 [97 76 49 65 49’]  13 27 38 49 [76 97 65 49’]  13 27 38 49 49’ [9765 76]  13 27 38 49 49’ 65 [9776]  13 27 38 49 49’ 65 76 97 图6.7直接选择排序的过程 最大优点是易读。缺点是每次都要从未排序的子序列中逐一查找出最小元素,效率低下。

  24. 【例6.9】直接选择排序 • void SelectSort(const int* pslst, const int &last) • { • int i, j, k,temp; • for(i=0;i<last;i++) • { • k=i; temp= *(pslst+ i); • for(j=i+1;j<=last;j++) //j=i有误!先找到最小的元素 • if(*(pslst+ j)<temp) { • k=j; temp=*(pslst+ j) ; • } • if ( k != i ){ //k>i也行。后进行交换 • temp=*(pslst+ i) ; • *(pslst+ i) =*(pslst+ k) ; • *(pslst+ k)=temp; • } • } • }

More Related