常用的十种排序
1、直接插入排序
最好O(n),最坏时间O(n^2),较稳定
基本思想:在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
#include <iostream> using namespace std; int main() { int a[]={5,2,6,3,9}; int len=sizeof(a)/sizeof(a[0]); for(int i=1;i<len;++i) { if(a[i]<a[i-1]) { int t=a[i],j; for(j=i-1;j>=0&&a[j]>t;--j) a[j+1]=a[j]; a[j+1]=t; } } for(int i=0;i<len;++i) cout<<a[i]<<" "; cout<<endl; return 0; }
2、希尔排序
时间复杂度:O(n*log(n)),不稳定
由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。
直接插入排序的的步长是为1的,而希尔排序向前比较是以一定步长向前比较。
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> arr{5,2,6,3,9}; for(int gap=arr.size()/2;gap>0;gap/=2)//步长 { for(int i=gap;i<arr.size();++i)//和直接插入排序一样,只不过是每次向前移动k步比较而不是移动一步比较 { int tmp=arr[i]; int j=i-gap; while(j>=0&&arr[j]>tmp) { arr[j+1]=arr[j]; j-=gap; } arr[j+gap]=tmp; } } for_each(arr.begin(),arr.end(),[](int i)->void{cout<<i<<" ";}); cout<<endl; return 0; }
3、简单选择排序
最好:O(n^2),最坏:O(n^2),不稳定
基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> arr{5,2,6,3,9}; for(int i=0;i<arr.size()-1;++i) { int minIndex=i; for(int j=i+1;j<arr.size();++j) { if(arr[j]<arr[minIndex]) minIndex=j; } if(minIndex!=i) swap(arr[minIndex],arr[i]); } for_each(arr.begin(),arr.end(),[](int i)->void{cout<<i<<" ";}); cout<<endl; return 0; }
4、堆排序
最好:nlog(n),最坏:nlog(n),不稳定
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
初建堆:
将一个任意序列看成是对应的完全二叉树,由于叶结点可以视为单元素的堆,因而可以反复利用上述调整的算法,自底向上逐层把所有子树调整为堆,直到整个完全二叉树为堆。最后一个非叶节点位于n/2(向下取整)个位置,n为二叉树结点数目,因此,筛选从n/2(向下取整)个结点开始,逐层向上倒退,知道根节点。
调整堆:
这是为了保持堆的特性而做的一个操作。对某一个节点为根的子树做堆调整,其实就是将该根节点进行“下沉”操作(具体是通过和子节点交换完成的),一直下沉到合适的位置,使得刚才的子树满足堆的性质。
- 在对应的数组元素A[i], 左孩子A[LEFT(i)], 和右孩子A[RIGHT(i)]中找到最大的那一个,将其下标存储在largest中。
- 如果A[i]已经就是最大的元素,则程序直接结束。
- 否则,i的某个子结点为最大的元素,将A[largest]与A[i]交换。
- 再从交换的子节点开始,重复1,2,3步,直至叶子节点,算完成一次堆调整。
这里需要提一下的是,一般做一次堆调整的时间复杂度为log(n)。
堆排序:
数组储存成堆的形式之后,第一次将A[0]与A[n - 1]交换,再对A[0…n-2]重新恢复堆。第二次将A[0]与A[n-2]交换,再对A[0…n-3]重新恢复堆,重复这样的操作直到A[0]与A[1]交换。由于每次都是将最小的数据并入到后面的有序区间,故操作完成后整个数组就有序了。
#include <iostream> #include <vector> using namespace std; /* 对于具有n个节点的完全二叉树,如果按照从上(根节点)到下(叶节点)和从左到右的顺序对二叉树中的所有节点从0开始到n-1进行编号,则对于任意的下标为k的节点,有: 如果k=0,则它是根节点,它没有父节点;如果k>0,则它的父节点的下标为[(i-1)/2]; 如果2k+1 <= n-1,则下标为k的节点的左子结点的下标为2k+1;否则,下标为k的节点没有左子结点. 如果2k+2 <= n-1,则下标为k的节点的右子节点的下标为2k+2;否则,下标为k的节点没有右子节点 */ class HeapSort { private: void adjustHeap(vector<int>& arr,int start,int end) { //2.调整堆:已知arr[start...end]中除关键字arr[start]之外均满足堆的定义 //本函数调整arr[start]的关键字,使arr[start,end]成为一个大根堆 int res=arr[start]; for(int j=start*2+1;j<=end;j=j*2+1) { if(j<end&&arr[j]<arr[j+1])//找出左右子树中最大的 ++j; if(res>arr[j]) break; arr[start]=arr[j]; start=j;//因为j和start交换了,所以要更新start的值;向下调整 } arr[start]=res; } public: void heapSort(vector<int>& arr) { int len=arr.size(); //1.初建堆 for(int i=len/2-1;i>=0;--i)//可以把数组中len/2-1后的元素看做单根堆,均满足堆的定义;所以向上调整 adjustHeap(arr,i,len-1); //堆排序 for(int i=len-1;i>0;--i) { swap(arr[0],arr[i]); adjustHeap(arr,0,i-1); } return ; } }; int main() { vector<int> arr{54,35,48,36,27,12,44,44,8,14,26,17,28}; HeapSort hs; hs.heapSort(arr); for(auto i:arr) cout<<i<<" "; cout<<endl; return 0; }
#include <iostream> #include <vector> #include <algorithm> using namespace std; class Heap_sort { public: void build_heap(vector<int> &v); void adjust_heap(vector<int> &v,vector<int>::iterator i,vector<int>::iterator dis); void sort_heap(vector<int> &v); vector<int>::iterator left_child(vector<int> &v,vector<int>::iterator i); vector<int>::iterator right_child(vector<int> &v,vector<int>::iterator i); }; //获取左节点下标 vector<int>::iterator Heap_sort::left_child(vector<int> &v,vector<int>::iterator i) { advance(i,distance(v.begin(),i)); return i; } //获取右节点下标 vector<int>::iterator Heap_sort::right_child(vector<int> &v,vector<int>::iterator i) { advance(i,distance(v.begin(),i)+1); return i; } //调整堆 void Heap_sort::adjust_heap(vector<int> &v,vector<int>::iterator i,vector<int>::iterator dis) { vector<int>::iterator l=left_child(v,i); vector<int>::iterator r=right_child(v,i); vector<int>::iterator largest=v.begin(); if((*i)<(*l)&&(l<dis)) largest=l; else largest=i; if((*largest)<(*r)&&(r<dis)) largest=r; //建的是大顶锥 if(largest!=i) { swap(*largest,*i); adjust_heap(v,largest,dis); } } //初建堆 void Heap_sort::build_heap(vector<int> &v) { for(vector<int>::iterator i=v.begin()+v.size()/2-1;i!=--v.begin();--i) adjust_heap(v,i,v.end()); } //堆排序 void Heap_sort::sort_heap(vector<int> &v) { build_heap(v);//堆排序之前应该先初建堆 for(auto i=--v.end();i!=--v.begin();--i) { swap(*i,*(v.begin()));//交换第一个元素(最大的)与最后一个元素 adjust_heap(v,v.begin(),i);//交换完之后第一个元素不是最大的,要调整堆使第一个元素最大 } } int main() { vector<int> v{70,30,40,10,80,20,90,100,75,60,45};//看做完全二叉树 Heap_sort hs;//创建堆排序的对象 hs.sort_heap(v); for(auto i:v) cout<<i<<" "; cout<<endl; return 0; }
5、冒泡排序
o(n^2),稳定
基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。
#include <iostream> #include <vector> using namespace std; int main() { vector<int> arr{70,30,40,10,80,20,90,100,75,60,45}; int len=arr.size(); bool flag=true; for(int i=0;i<len-1&&flag;++i) { flag=false; for(int j=0;j<len-i;++j) { if(arr[j]>arr[j+1]) { swap(arr[j],arr[j+1]); flag=true; } } } for(auto i:arr) cout<<i<<" "; cout<<endl; return 0; }
双向冒泡排序算法步骤
- 比较相邻两个元素的大小。如果前一个元素比后一个元素大,则两元素位置交换
- 对数组中所有元素的组合进行第1步的比较
- 奇数趟时从左向右进行比较和交换
- 偶数趟时从右向左进行比较和交换、
- 当从左端开始遍历的指针与从右端开始遍历的指针相遇时,排序结束
//双向冒泡排序 #include <iostream> #include <algorithm> using namespace std; void per_sort(int a[],int len,int per_index) { for(int i=per_index+1;i<len;++i) if(a[i]<a[per_index]) swap(a[i],a[per_index]); } void back_sort(int a[],int len,int back_index) { for(int i=back_index-1;i>=0;--i) if(a[i]>a[back_index]) swap(a[i],a[back_index]); } void two_way_bubble_sort(int a[],int len) { int per_index=0,back_index=len-1; while(per_index<back_index) { per_sort(a,len,per_index); ++per_index; if(per_index>back_index) break; back_sort(a,len,back_index); --back_index; } } int main() { int a[]={70,30,40,10,80,20,90,100,75,60,45}; int length=sizeof(a)/sizeof(int); two_way_bubble_sort(a,length); for(int i=0;i<length;++i) cout<<a[i]<<" "; cout<<endl; return 0; }
6、快速排序
最好:O(nlog(n)),最坏:O(n^2),不稳定
基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。
假设待划分的序列为a[left],a[left+1]......a[right],首先将基准记录a[left]移致变量x中,使a[left]相当于空单元,然后反复进行如下两个扫描过程,知道left和right相遇。
1.left从右向左扫描,直到a[right]<x,将a[right]移至空单元a[left]中,此时a[right]相当于空单元
2.left从左向右扫描,直到a[left]>x,将a[left]移到空单元a[right],此时a[left]相当于空单元。
当left和right相遇时,a[left]或a[right]相当于空单元,且a[left]左边均比它小,右边均比它大,最后将基准记录移至a[left]中,完成了一次划分,再对a[left]的左子表和右子表进行同样的划分。
#include <iostream> #include <vector> using namespace std; class QuickSort { private: int pass(vector<int>& arr,int left,int right) { int temp=arr[left]; while(left<right) { while(right>left&&temp<=arr[right]) --right; if(left<right) arr[left++]=arr[right]; while(right>left&&temp>arr[left]) ++left; if(left<right) arr[right--]=arr[left]; } arr[left]=temp; return left; } public: void quickSort(vector<int>& arr,int start,int end) { if(start<end) { int mid=pass(arr,start,end); quickSort(arr,start,mid-1); quickSort(arr,mid+1,end); } return ; } }; int main() { vector<int> arr{70,30,40,10,80}; QuickSort qs; qs.quickSort(arr,0,5); for(auto i:arr) cout<<i<<" "; cout<<endl; return 0; }
三路快排
在排序过程中分为比基准元素小的部分:[left,lt],等于基准元素的部分:[lt+1,i),大于基准元素的部分:[gt,r]
void quick_sort3(vector<int>& arr,int left,int right) { if(left>=right) return ; int v=arr[left]; int lt=left; int i=lt+1; int gt=right+1;//刚开始大于基准元素部分为空,所以gt=right+1 while(i<gt) { if(arr[i]<v) { swap(arr[i],arr[lt+1]); ++lt; ++i; } else if(arr[i]>v) { swap(arr[i],arr[gt-1]); --gt; //++i;//换过来的此元素可能比v小所以要再次比较,不能++i } else { ++i; } } swap(arr[left],arr[lt]);//相当于等于基准元素部分向左扩一位 quick_sort3(arr,left,lt-1); quick_sort3(arr,gt,right); }
单链表快排
slow指针及左边的元素都小于基准元素,fast指针用来遍历,当遇到比基准元素小的时候先slow后移,此时slow指向的肯定比基准元素大,在交换slow和fast指向的元素的值,相当于slow向右扩充。
ListNode* partition(ListNode* start, ListNode* end) { ListNode* slow=start; ListNode* fast=slow->next; int key=start->val; while(fast!=end) { if(fast->val<key) { slow=slow->next; swap(slow->val,fast->val); } fast=fast->next; } swap(slow->val,start->val); return slow; } void quick_sort(ListNode* start,ListNode* end) { if(start==end) return ; ListNode* mid=partition(start,end); quick_sort(start,mid); quick_sort(mid->next,end); }
7、归并排序
最好:O(nlog(n)),最坏:O(nlog(n)),稳定
算法思想:
假设初始序列含有n个记录,首先将这n个记录看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到N/2(向上取整)个长度为的有序子序列,在此基础上,在对长度为2的有序子序列进行两两归并,得到若干个长度为4的子序列,重复,知道得到长度为n的有序序列为止。
tmp存放在归并时完成归并的数组,然后再将其赋值给原数组。
class Solution { private: void merge(vector<int> &nums, int left, int mid, int right) { int i = left, j = mid + 1, index = 0; int count = 0; vector<int> tmp(right - left + 1); while (i <= mid && j <= right) { if (nums[i] <= nums[j]) { tmp[index++] = nums[i++]; } else { tmp[index++] = nums[j++]; } } while (i <= mid) { tmp[index++] = nums[i++]; } while (j <= right) { tmp[index++] = nums[j++]; } for (i = 0; i < tmp.size(); ++i) { nums[left + i] = tmp[i]; } return ; } void mergeSort(vector<int> &nums, int left, int right) { if (left >= right) { return ; } int mid = left + (right - left) / 2; mergeSort(nums, left, mid); mergeSort(nums, mid + 1, right); merge(nums, left, mid, right); } public: int reversePairs(vector<int>& nums) { return mergeSort(nums, 0, nums.size() - 1); } };
单链表归并
ListNode* merge(ListNode* l1,ListNode* l2) { ListNode* H=new ListNode(1); ListNode* l=H; while(l1&&l2) { if(l1->val<=l2->val) { l->next=l1; l1=l1->next; } else { l->next=l2; l2=l2->next; } l=l->next; } if(l1) l->next=l1; if(l2) l->next=l2; return H->next; } ListNode* mergeList(ListNode* head) { if(head==nullptr||head->next==nullptr) return head; ListNode* pre=nullptr; ListNode* slow=head; ListNode* fast=head; while(fast) { pre=slow; slow=slow->next; fast=fast->next; if(fast) fast=fast->next; } if(pre) pre->next=nullptr; ListNode* l1=mergeList(head); ListNode* l2=mergeList(slow); return merge(l1,l2); }
8、基数排序
平均时间复杂度:O(n),最好:O(n),最坏:O(n),稳定
基本思想:
将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
整个算法过程描述如下:
1、将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。
2、从最低位开始,依次进行一次排序。
3、这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
基数排序的时间复杂度是 O(k•n),其中n是排序元素个数,k是数字位数。
#include <iostream> #include <vector> #include <algorithm> using namespace std; class Radix_sort { public: void radix_sort(vector<int> &v); private: void count_sort(vector<int> &v,int exp); }; void Radix_sort::count_sort(vector<int> &v,int exp) { vector<int> tmp(10,0),ot(v.size(),0); for(int i=0;i<v.size();++i) ++(tmp.at((v.at(i)/exp)%10)); for(int i=1;i<10;++i) tmp.at(i)+=tmp.at(i-1); for(int i=v.size()-1;i>-1;--i) ot.at(--(tmp.at(v.at(i)/exp%10)))=v.at(i); copy(ot.begin(),ot.end(),v.begin()); } void Radix_sort::radix_sort(vector<int> &v) { int Max=*max_element(v.begin(),v.end()); for(int exp=1;Max/exp>0;exp*=10) count_sort(v,exp); } int main() { vector<int> v{70,30,40,10,80,20,90,100,75,60,45}; Radix_sort rs; rs.radix_sort(v); for(auto i:v) cout<<i<<" "; cout<<endl; return 0; }
#include<iostream> using namespace std; #define N 10 class RadixSort { public: int* radixSort(int* A, int n,int radix) //基数排序:radix为关键字最高位数 { int temp[10][N]={0},order[10]={0}; int m=(int)pow((double)10,radix-1),base=1; while(base<=m) { int i,k; for(i=0;i<n;i++) { int lsd=(A[i]/base)%10; temp[lsd][order[lsd]]=A[i]; order[lsd]++; } for(i=0,k=0;i<10;i++) { if(order[i]) { int j; for(j=0;j<order[i];j++,k++) A[k]=temp[i][j]; } order[i]=0; } base*=10; } return A; } }; int main() { int arr[]={5412,351,4821,362,127,12,441,414,8,1499,2226,5717,268}; RadixSort a; a.radixSort(arr,13,4); for(int i=0;i<13;i++) cout<<arr[i]<<" "; cout<<endl; return 0; }
9、桶排序
平均时间复杂度:O(n),最好:O(n),最坏:O(n),不稳定
算法描述和分析
- 设置一个定量的数组当作空桶子。
- 寻访串行,并且把项目一个一个放到对应的桶子去。
- 对每个不是空的桶子进行排序。
- 从不是空的桶子里把项目再放回原来的串行中。
#include <iostream> #include <algorithm> #include <vector> #include <cstdlib> #include <ctime> using namespace std; class Rand { public: int operator() () { //srand((unsigned)time(NULL)); return rand()%(100-1)+1; } }; class Bucket_sort { public: void bucket_sort(vector<int> &v); }; void Bucket_sort::bucket_sort(vector<int> &v) { //1.设置10个桶 vector<vector<int> > tmp(10,vector<int>(distance(v.begin(),v.end()))); //vector<int> count(10,0);//桶 //2.获得数据的平均值 double avg=(*max_element(v.begin(),v.end())-*min_element(v.begin(),v.end())+1)/10.0; //cout<<avg<<endl; for(auto it=v.begin();it!=v.end();++it) { //3.确定桶号 int num=(*it-*min_element(v.begin(),v.end()))/avg; //cout<<num<<endl; //4.把数据装入桶中 if(tmp[num][0]) { //此桶中有数据,用直接插入排序 int len=1; for(int i=1;i<10;++i) if(tmp[num][i]) ++len; else break; //int t=*it; int j; for(j=len-1;j>=0;--j) { if(*it<tmp[num][j]) tmp[num][j+1]=tmp[num][j]; else break; } tmp[num][j+1]=*it; } else//桶中无数据可以直接插入 tmp[num][0]=*it; } //把桶中的数据按顺序放到原来的数组 v.clear(); for(int i=0;i<10;++i) { if(tmp[i][0])//如果桶中有数据 for(int j=0;j<10&&tmp[i][j];++j) v.push_back(tmp[i][j]); } } int main() { vector<int> arr(10); generate(arr.begin(),arr.end(),Rand()); cout<<" 产生的随机数:"<<endl; for(auto i:arr) cout<<i<<" "; cout<<endl; cout<<" 排序后的数字:"<<endl; Bucket_sort bs; bs.bucket_sort(arr); for(auto i:arr) cout<<i<<" "; cout<<endl; return 0; }
10、计数排序
算法简介
计数排序(Counting sort)是一种稳定的排序算法。计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i+Min的元素的个数。然后根据数组C来将A中的元素排到正确的位置。它只能对整数进行排序。
- 找出待排序的数组中最大和最小的元素
- 统计数组中每个值为i的元素出现的次数,存入数组C的第i项
- 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
- 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
计数排序是一种以空间换时间的排序算法,并且只适用于待排序列中所有的数较为集中时,比如一组序列中的数据为0 1 2 3 4 999;就得开辟1000个辅助空间。
#include <iostream> #include <vector> #include <algorithm> using namespace std; class Count_sort { public: void count_sort(vector<int> &v); }; void Count_sort::count_sort(vector<int> &v) { int Min=*min_element(v.begin(),v.end()); int Max=*max_element(v.begin(),v.end()); vector<int> count(Max-Min+1);//数据范围 for(int i=0;i<v.size();++i)//把数据存入计数数组,计算每个下表的数字个数 ++(count.at(v.at(i)-Min)); for(int i=0,index=0;i<Max-Min+1;++i) while((count.at(i))--) v.at(index++)=i+Min; } int main() { vector<int> v{5,6,3,8,4,5,2,6,7,6,3,9}; Count_sort cs; cs.count_sort(v); for(auto i:v) cout<<i<<" "; cout<<endl; return 0; }
#include<iostream> #include<cstdlib> using namespace std; class CountingSort { public: int* countingSort(int* A, int n) //¼ÆÊýÅÅÐò { int i,j,min,max; for(i=1,min=max=A[0];i<n;i++) { if(A[i]<=min) min=A[i]; if(A[i]>max) max=A[i]; } int *counts=(int *)calloc(max-min+1,sizeof(int)); if(!counts) exit(-1); for(i=0;i<n;i++) counts[A[i]-min]++; for(i=0,j=0;i<max-min+1;i++) while(counts[i]) { A[j]=i+min; counts[i]--; j++; } free(counts); counts=NULL; return A; } }; int main() { int arr[]={54,35,48,36,27,12,44,44,8,14,26,17,28}; CountingSort a; a.countingSort(arr,13); for(int i=0;i<13;i++) cout<<arr[i]<<" "; cout<<endl; return 0; }
分块查找
1.将待查找关键字k与索引表中的关键字进行比较,已确定待查找记录所在的块,可用折半查找或顺序查找
2.进一步用顺序查找,在相应的块内查找关键字为k的元素。
#include <iostream> #include <vector> #include <algorithm> using namespace std; struct block { int start,key; }block[3]; typedef struct block B; bool cmp(const B &x,const B &y) { if(x.key<=y.key) return true; else return false; } int block_search(vector<int> v,int num) { //分为三块,计算每个块内有多少元素 int step=ceil(v.size()/3.0);//其实也就是块的长度,最后一个元素的下标 for(int i=0,j=0;i<3;++i)//3块 { block[i].start=j; if(j+step<v.size())//最后一个块内的元素不一定等于setp,防止越界 j+=step; else j=v.size(); block[i].key=*max_element(v.begin()+block[i].start,v.begin()+j);//key为每个块内的最大的元素 } sort(block,block+3,cmp); //找到第一个key小于num的block int i=0; for(;block[i].key<num&&i<3;++i); int j=block[i].start; for(;j<(block[i].start+step)&&((v.at(j))!=num);++j); if(j>=block[i].start+step) { cerr<<" 要查找的数不存在"<<endl; return -1; } return v.at(j); } int main() { vector<int> v{70,30,40,10,80,20,90,100,75,60,45}; cout<<block_search(v,80)<<endl; return 0; }
计算式查找法
#include <iostream> #include <vector> #include <vector> using namespace std; typedef struct Hash { int key; struct Hash *next; Hash() { key=0; next=nullptr; } }Hash; Hash *insert_hash(Hash *head,const int &key) { Hash *t=new Hash(); t->key=key; Hash *p0=head,*p1=nullptr; if(!head) { head=t; t->next=nullptr; } else { while((p0->key<t->key)&&(p0->next!=nullptr)) { p1=p0; p0=p0->next; } if(t->key<=p0->key)//插到当前节点的前面 { if(p0==head)//且当前节点是第一个节点 { head=t; head->next=p0; } else { p1->next=t; t->next=p0; } } else//插入到当前节点的后面 { p0->next=t; t->next=nullptr; } } return head; } pair<int,int> hash_search(Hash *h,int key) { int j=0; Hash *t=h; while(t) { if(t->key==key) break; ++j; t=t->next; } if(!t) return make_pair(-1,-1); else return make_pair(-1,j); } int main() { vector<Hash*> h(100); vector<int> v{70,30,40,10,48,24,90,100,75,60,45}; for(int i=0;i<h.size();++i) h.at(i)=nullptr; for(int i=0;i<v.size();++i) { int t=v.at(i)%(v.size()+1); h.at(t)=insert_hash(h.at(t),v.at(i)); } for(int i=0;i<v.size();++i) { Hash *t=h.at(i); while(t) { cout<<t->key<<" "; t=t->next; } cout<<endl; } pair<int,int> p; for(int i=0;i<v.size();++i) { p=hash_search(h.at(i),75); if(p.second!=-1) { p.first=i; break; } } cout<<"row:"<<p.first<<" col:"<<p.second<<endl; return 0; }