1 / 33

第 15 讲 查找和排序

第 15 讲 查找和排序. 领会和掌握 HASH 查找原理和方法 掌握 HASH 查找解决地址冲突的方法: 线性探测再散列和链地址法 掌握线性探测再散列和链地址法的函数编写 领会和掌握排序方法:简单插入、简单选择、基数排序. 什么是查找. 关键字: 就是数据元素中可以标识该数据元素 的数据项, Keyword 。 查找: 就是根据给定的关键字值,在一组数据 元素中确定一个其关键字值等于给定值 的数据元素的过程。若存在这样的数据 元素,则称查找是成功的;否则称查找 不成功。 search

Download Presentation

第 15 讲 查找和排序

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. 第15讲 查找和排序 • 领会和掌握HASH查找原理和方法 • 掌握HASH查找解决地址冲突的方法: 线性探测再散列和链地址法 • 掌握线性探测再散列和链地址法的函数编写 • 领会和掌握排序方法:简单插入、简单选择、基数排序

  2. 什么是查找 关键字:就是数据元素中可以标识该数据元素 的数据项,Keyword。 查找:就是根据给定的关键字值,在一组数据 元素中确定一个其关键字值等于给定值 的数据元素的过程。若存在这样的数据 元素,则称查找是成功的;否则称查找 不成功。search 查找表:待查的数据元素集合

  3. 查找算法的评价 衡量一个算法的标准主要有两个:时间和空间 查找算法通常只需要一个或几个辅助空间,因 此主要看查找算法的查找速度(即时间)。 在查找算法中,基本运算是给定值与关键字值 的比较,即算法的主要时间是花费在“比较”上 的。所以评价一个查找算法的好坏主要看比较 次数的多少。

  4. 开始 折半查找的算法 0->mid hig>=low (hig+low)/2->mid A[mid]==X mid+1->low A[mid]>X mid-1->hig 返回mid 折半查找的算法 结束

  5. 查找表的存储结构采用顺序表类 template <class datatype> class search_list //查找表类的定义 { private: datatype *data; //数据元素数组的首地址 int maxsize; //查找表的最大可能长度 int last; //表尾数据元素的下标 public: search_list() //创建100个元素的线性表的构造函数 { maxsize=100; data=new datatype[maxsize]; last=-1; //last为―1表示为空表 } search_list(int sz) //创建sz个元素的线性表的构造函数 { if(sz>0) //判定sz是否大于0 maxsize=sz; else maxsize=100; data=new datatype[maxsize]; last=-1; //last为-1表示为空表 }

  6. bool isempty(){ return last==-1?true:false; } //判空表 bool isfull(){ return last==maxsize-1; } //判表满 int length(){ return last+1; } //求表长 bool getdata(int i,datatype &x) //取元素 { i--; if (i>=0&&i<=last) { x = data[i]; return true; }; return false; } bool get_prior(int i,datatype &x); //取前驱元素 bool get_succ(int i,datatype &x); //取后继元素 bool replace(int i,datatype x); //置换元素 bool insert_data(int i,datatype x); //向查找表中插入一个元素 bool delete_data(int i); //从查找表中删除一个元素 void print_list(); //打印查找表中所有元素 bool create_hash1(datatype *pa,int n); //创建线性探测哈希表 bool create_hash2(datatype *pa,int n); //创建二次探测哈希表 bool create_hash3(datatype *pa,int n); //创建链地址法哈希表 int hash_find1(datatype x); //线性探测的哈希查找 int hash_find2(datatype x); //二次探测的哈希查找 int hash_find3(datatype x); //链地址的哈希查找 ~search_list(){ delete[]data; } //析构函数 };

  7. 什么是哈希查找 哈希查找方法是对关键字进行某种函数公式 运算后直接得到数据元素的存 贮位置(或地址),这种函数 公式称哈希函数 在一块连续的内存空间采用哈希查找方法将 所有数据元素重新组织建立起来的查找表就 称为哈希表

  8. D=H(keyword) D=keyword-03191000+49 D=keyword%03191000+49 50 51 52 53 54 81

  9. 用除留取余函数建立哈希表 D=keyword%/m 设关键字序列为(32,13,49,55,22,38,21) 0 1 2 3 4 5 6 55 21 地址冲突:不同的关键字值对应到同一个存贮位置的现 象称为冲突。 即K1≠K2,但H(K1)=H(K2)

  10. 线性探测再散列 D=H(keyword) ND=(D+d i)%m d i依次为1,2,3,……,m-1 0 1 2 3 4 5 6 55 21

  11. template<class datatype> bool search_list<datatype>:: create_hash1(datatype *pa,int n) { int addr,new_addr,di; int hashlist_length; if(n<0||(n+n/10+1)>MAXSIZE) { cout<<"n的值有错误,不能创建哈希表!\n"; return false; } hashlist_length = n+n/10+1; for(int i=0;i<hashlist_length;i++) data[i]=0; last = hashlist_length - 1; for(i=0;i<n;i++) { addr = pa[i] % hashlist_length; new_addr = addr; di = 1; while(data[new_addr]) { new_addr = (addr+di) % hashlist_length; di++; } data[new_addr] = pa[i]; } return true; } 第1步:检验n的合法性,若n不合法,结束算法 第2步:计算哈希表的长度n+n/10+1; 第3步:将整个哈希表的元素置0; 第4步:last置成哈希表的长度减1; 第5步:循环n次做下面步骤; 第6步:计算第i个数组元素地址,地址不冲突存 放该元素,返回第5步; 第7步:抵制冲突,循环计算新地址,直到不冲 突,存放该元素,返回第5步; 建立哈希表函数

  12. template<class datatype> int search_list<datatype>:: hash_find1(datatype x) { int addr,new_addr,di; datatype data_key=x; addr=data_key%(last+1); new_addr=addr; di=1; while ((data[new_addr]!=x)&& (data[new_addr]!=0)) { new_addr=(addr+di)%(last+1); di++; } if(data[new_addr]==x) return new_addr+1; else return -1; } 线性探测再散列哈希查找 第一步:对给定值keyword,计算哈希地址I=H(keywood) 第二步:若表中I地址的单元为0,则查找失败。否则执行第二步 第三步:若表中I地址的单元值等于k,则查找成功,否则,执行 第四步; 第四步:重复计算冲突后的下一个存贮地址d k=R(d k-1)直到 表中d k的单元为0或单元值等于keywood为止。若d k 下标的单元值等于keywood,则查找成功,否则查找 失败。

  13. 测试主函数 • #include<iostream.h> • #include<stdlib.h> • template<class datatype> • void search_list<datatype>::print_list() //打印查找表中所有元素 • { • for(int i=0;i<=last;i++) • { • cout<<data[i]<<" "; • } • cout<<endl; • } • int main() • { int a[7]={32,13,49,55,22,38,21}; //7个元素数组 • int i,j; • search_list<int> hash_list1(10); //声明元素类型为整数的对像 • hash_list1.create_hash1(a,7); //用线性探测建立哈希表 • for(i=0;i<7;i++) cout<<a[i]<<" "; //输出原始数据 • cout<<endl; • hash_list1.print_list(); //打印哈希表 • for(i=0;i<7;i++) • cout<<hash_list1.hash_find1(a[i])<<" "; //循环查找每一个数据 • cout<<hash_list1.hash_find1 (320)<<" "; //验证查找不成功 • cout<<hash_list1.hash_find1(9)<<" "; //验证查找不成功 • cout<<endl; const int array_length = 80;

  14. int aa[array_length]; • int data_key; • j=1; • for(i=0;i<array_length;i++) //随机生成80个元素 • { • aa[i]=1000+rand(); • if(j>10) • { • cout<<endl; • j=1; • } • cout<<aa[i]<<" "; • j++; • } • search_list<int> hash_list2(100); //声明元素类型为整数的对像 • hash_list2.create_hash1(aa,array_length); //创建哈希表 • cout<<endl<<endl; • j=1; • for(i=0;i<hash_list2.length();i++) //输出哈希表所有元素 • { • hash_list2.getdata(i+1,data_key); • if(j>10) • { • cout<<endl; • j=1; • } • cout<<data_key<<" "; • j++; • } • cout<<endl; • for(i=0;i<array_length;i++) //循环查找每个元素 • cout<<hash_list2.hash_find1(aa[i])<<" "; • cout<<endl; • return 0; • }

  15. 测试验证线性探测再散列查找的正确性 第一步:复制哈希表的定义 第二步:复制建立哈希表的函数 第三步:复制哈希查找函数 第四步:复制测试主函数 第五步:编译、连接、运行

  16. 链地址法的哈希查找 (地址冲突的元素建立单链表)

  17. 关键字序列为:19,14,23,2,68,16,4 线性探测再散列的哈希表 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 链地址法的哈希表 2 16 68

  18. template<class datatype> bool search_list<datatype>::create_hash3(int *pa,int n) { int addr; if(n>MAXSIZE) { cout<<"n的值有错误,不能创建哈希表!\n"; return false; } for(int i=0;i<n;i++) { data[i].element=0; data[i].phead=NULL; } last = n - 1; for(i=0;i<n;i++) { addr = pa[i] % n; if(data[addr].element) insert_head(&data[addr].phead,pa[i]); else data[addr].element = pa[i]; } return true; } 第1步:判定实际元素个数不大于表的最大限度; 第2步:将主表(即顺序表类)中所有元素清“空”; 第3步:循环取n个待进入哈希表的元素,做下面步骤; 第4步:计算哈希地址; 第5步:判断该地址的数据域为0否,若为0,则装入元素 ,返回第3步; 第6步:将元素插入该地址域所指向的单链表中,返回第3步 创建链地址法哈希表函数

  19. template<class datatype> //链地址法查找函数 bool search_list<datatype>:: hash_find3(const int &x,int &result) { int addr,i; result = 0; addr = x % (last+1); //计算哈希地址 if((data[addr].element!=x)&&(data[addr].element!=0)) { if(data[addr].phead==NULL) //空链表,查找失败 { cout<<x<<"查找失败!\n"; return false; } else { for(i=1;i<=data[addr].phead->length();i++) { data[addr].phead->get_data(i,result); if(result==x) return true; } cout<<x<<"查找失败!\n"; return false; } } else { if(data[addr].element!=x) //顺序表的元素是否相等 { cout<<x<<"查找失败!\n"; return false; } else { result = data[addr].element; //查找成功 return true; } } } 链地址法查找函数

  20. 作业1:编写折半查找函数 作业2:编写二次探测再散列方法 的建立与查找HASH表函数 作业2:本章练习题2 作业3:本章练习题3

  21. 什么是排序 假设有n个数据元素的序列为{R1,R2,…,Rn} 其相应的排序码为{K1,K2,…, Kn} 所谓排序就是将记录按排序码非递减(或非递增)的次序排列起来,形成新的有序序列的过程 排序码是数据元素中一个(或多个)数据项,可以是关键字,也可以不是关键字 将待排序的数据元素序列称为排序表

  22. 排序表采用顺序表类 template <class datatype> class seqlist //排序表类的定义 { private: //数据成员定义等同于顺序表类 datatype *data; int maxsize; int last; public: //函数成员定义类似于顺序表类 seqlist() //创建100个元素的线性表 seqlist(int sz) //创建sz个元素的线性表 bool isempty(){ return last==-1; } //判空表 bool isfull(){ return last==maxsize-1;} //判表满 int length(){ return last+1; }; //求表长

  23. bool getdata(int i,datatype &x); //取元素 datatype 达datatype getdata1(int i) //不加检验的取出元素函数 bool replace(int i,datatype x) //置换元素 void setdata(int i,datatype x) //不检验的修改元素函数 void insert_data(int i,datatype x); //插入元素 void delete_data(int i); //删除元素 void print_list(); //显示表中所有元素 void insertsort(); //插入排序函数 void selectsort(); //选择排序函数 void bubble_sort(); //冒泡排序函数 int qpass(int low,int hig); //快速排序的划分函数 void quicksort(int low,int hig); //快速排序函数 };

  24. 简单插入排序 把n个元素的序列划分为两个子序列:一个为有序;另一个为无序 将无序子序列中的元素依次取出插入到有序子序列中,直到无序子 序列为空,整个排序结束。 若待排序数据元素的排序码序列是(18,12,10,12,30,16) 初始状态 〔18〕12 10 12 30 16 第1趟(i=2) 〔12 18〕10 12 30 16 第2趟(i=3) 〔10 12 18〕12 30 16 第3趟(i=4) 〔12 12 12 18〕30 16 第4趟(i=5) 〔10 12 12 18 30〕16 第5趟(i=6) 〔10 12 12 16 18 30〕

  25. template<class datatype> Void seqlist<datatype>::insertsort( ) { int i,j; datatypetemp; insert_data(1,temp); for(i=2;i<=last;i++) { data[0]=data[i]; //每趟需插入的元素放表头 j=i-1; while(data[0]<data[j]) { data[j+1]=data[j]; j--; } data[j+1]=data[0]; } delete_data(1); }

  26. 简单选择排序 第1步:在n个数据元素中找出排序码最小的数据元素,与第1个元 素交换 第2步:在n-1个数据元素中找出排序码最小的数据元素,与第2个 元素交换 第i步:在n-i+1个数据元素中找出排序码最小的数据元素,与第i 个元素交换 初始状态 〔2 7 2 2 3 1〕 第1趟(i=1) 1 〔 7 2 2 3 2〕 第2趟(i=2) 1 2〔 7 2 3 2〕 第3趟(i=3) 1 2 2 〔7 3 2〕 第4趟(i=4) 1 2 2 2 〔37〕 第5趟(i=5) 1 2 2 2 3 〔7〕

  27. template<class datatype> void seqlist<datatype>::selectsort() { int i,j,k; int temp; for(i=0;i<last;i++) { k=i; //初始定位 for(j=i+1;j<=last;j++) if(data[j]<data[k]) k=j; if(i!=k) { temp=data[k]; data[k]=data[i]; data[i]=temp; } } };

  28. 冒泡排序 • 32 98 14 10 77 66 88 55 92

  29. template<class datatype> void seqlist<datatype>::bubble_sort( ) { int i,j,tmp; for(i=0; i<last; i=i+1) for(j=last-1; j>i; j=j-1) if(data[j-1]>data[j]) { tmp = data[j-1]; data[j-1] = data[j]; data[j] = tmp; } }

  30. template<class datatype> void seqlist<datatype>::bubble_sort( ) { int i,j,tmp; for(i=last-1; i>0; i=i-1) for(j=0; j<=i; j=j+1) if(data[j-1]>data[j]) { tmp = data[j-1]; data[j-1] = data[j]; data[j] = tmp; } }

  31. 基数排序 先根据所有排序码的最低位有效数字的大小重新递增排列; 再根据所有排序码的次低位有效数字的大小重新递增排列; 依此类推,直到最高位。 初始: 2478 7680 246 11 2333 950 902 7145 3446 92 第一趟 7680 950 11 902 92 2333 7145 246 3446 2478 第二趟 902 11 2333 7145 246 3446 950 2478 7680 92 第三趟 11 92 7145 246 2333 3446 2478 7680 902 950 第四趟 11 92 246 902 950 2333 2478 3446 7145 7680

  32. Void main() { int sort_table[N], barrel[10][N], counter[10]; int i,j,k,m,code,js=10; for(i=0;i<N;i++) sort_table[i]=10+rand(); for(j=1;j<=9;j++) { i=0; for(k=0;k<10;k++) counter[k]=0; for(k=0;k<N;k++) { code=sort_table[k]%js; code=code/(js/10); barrel[code][counter[code]]=sort_table[k]; counter[code]++; } for(k=0;k<10;k++) for(m=0;m<counter[k];m++) { sort_table[i]=barrel[k][m]; i++; } js*=10; } }

  33. 作业: 本章练习题目5 本章练习题目6

More Related