模板整理
1 int find(int x) 2 { 3 if(father[x]!=x)father[x]=find(father[x]); 4 return father[x]; 5 } 6 void u(int r1,int r2) 7 { 8 father[r2]=r1; 9 }
高精度系列
1 void add(int a[],int b[]) //a,b,c都为数组,分别存储被加数、加数、结果 2 { 3 int i=1,x=0; //x是进位 4 while ((i<=a数组长度)||(i<=b数组的长度)) 5 { 6 c[i]=a[i]+b[i]+x; //第i位相加并加上次的进位 7 x=c[i]/10; //向高位进位 8 c[i]%=10; //存储第i位的值 9 i++; //位置下标变量 10 } 11 }
排序
(1)选择排序
基本思想:每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在待排序的数列的最前,直到全部待排序的数据元素排完。
1 void SelectSort(int R[]) //对R[1..N]进行直接选择排序 2 { 3 for (int i=1;i<=n-1;i++) //做N - 1趟选择排序 4 { 5 K = I; 6 For (int j=i+1;j<=n;j++) //在当前无序区R[I..N]中选最小的元素R[K] 7 { 8 If (R[J] < R[K]) K = J; 9 } 10 If (K!=I) //交换R[I]和R[K] 11 { 12 Temp = R[I]; 13 R[I] = R[K]; 14 R[K] = Temp; 15 } 16 } 17 }
(2)桶排序
桶排序的思想是若待排序的记录的关键字在一个明显有限范围内(整型)时,可设计有限个有序桶,每个桶装入一个值(当然也可以装入若干个值),顺序输出各桶的值,将得到有序的序列。
#include<iostream> #include <cstring> using namespace std; Int main() { int b[101],k,I,n; memset(b,0,sizeof(b)); //初始化 cin>>n; for( i=1;I<=n;i++) { cin>>k; b[k]++; //将关键字等于k的值全部装入第k桶 } for( i=0; I<=100;i++) while (b[i]>0) {cout<<i<<" " ;b[i]--;} //输出排序结果 cout<<endl; }
(3)插入排序
插入排序是一种简单的排序方法,其算法的基本思想是: 假设待排序的数据存放在数组R[1..n]中,增加一个哨兵结点x。
1) R[1]自成1个有序区,无序区为R[2..n];
2) 从i=2起直至i=n为止,将R[i]放在恰当的位置,使R[1..i]数据序列有序;
① x:=R[i];
② 将x与前i-1个数比较 , j:=i-1; while x<a[j] do j:=j-1;
③ 将R数组的元素从j位置开始向后移动: for k:=i downto j do a[k]:=a[k-1];
④ R[j]=x;
3) 生成包含n个数据的有序区。
例如:设n=8,数组R中8个元素是: 36,25,48,12,65,43,20,58,执行插入排序程序后,其数据变动情况:
第0步:[36] 25 48 12 65 43 20 58
第1步:[25 36] 48 12 65 43 20 58
第2步:[25 36 48] 12 65 43 20 58
第3步:[12 25 36 48] 65 43 20 58
第4步:[12 25 36 48 65] 43 20 58
第5步:[12 25 36 43 48 65] 20 58
第6步:[12 20 25 36 43 48 65] 58
第7步:[12 20 25 36 43 48 58 65]
void insertsort(int r[]) //对r[1..n]按递增序进行插入排序,x是监视哨 { for (i=2;i<=n;i++) //依次插入r[2],...,r[n] { x=r[i]; j= i-1; While (x< r[j]) //查找r[i]的插入位置// { r[j+1] =r[j]; //将大于r[i]的元素后移// j--; } r[j+1] = x; //插入r[I] // } }
(4)快速排序
快速排序是对冒泡排序的一种改进。它的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
假设待排序的序列为{a[L],a[L+1],a[L+2],……,a[R]},首先任意选取一个记录(通常可选中间一个记作为枢轴或支点),然后重新排列其余记录,将所有关键字小于它的记录都放在左子序列中,所有关键字大于它的记录都放在右子序列中。由此可以将该“支点”记录所在的位置mid作分界线,将序列分割成两个子序列和。这个过程称作一趟快速排序(或一次划分)。
一趟快速排序的具体做法是:附设两个指针i和j,它们的初值分别为L和R,设枢轴记录取mid,则首先从j所指位置起向前搜索找到第一个关键字小于的mid的记录,然后从i所指位置起向后搜索,找到第一个关键字大于mid的记录,将它们互相交换,重复这两步直至i>j为止。
快速排序的时间的复杂性是O(nlog2n),速度快,但它是不稳定的排序方法。就平均时间而言,快速排序是目前被认为是最好的一种内部排序方法
由以上讨论可知,从时间上看,快速排序的平均性能优于前面讨论过的各种排序方法,但快速排序需一个栈空间来实现递归。若每一趟排序都将记录序列均匀地分割成长度相接近的两个子序列,则栈的最大深度为log(n+1)。
void qsort(int l,int r) { int i,j,mid,p; i=l; j=r; mid=a[(l+r) / 2]; //将当前序列在中间位置的数定义为分隔数 do { while (a[i]<mid) i++; //在左半部分寻找比中间数大的数 while (a[j]>mid) j--; //在右半部分寻找比中间数小的数 if (i<=j) { //若找到一组与排序目标不一致的数对则交换它们 p=a[i]; a[i]=a[j]; a[j]=p; i++; j--; //继续找 } } while (i<=j); //注意这里不能有等号 if (l<j) qsort(l,j); //若未到两个数的边界,则递归搜索左右区间 if (i<r) qsort(i,r); end;
(5)归并排序
归并排序 将两个或两个以上有序的数列(或有序表),合并成一个仍然有序的数列(有序表),这种操作称为归并操作。
这样的方法经常用于多个有序的数据文件归并成一个有序的数据文件。若将两个有序表合并成一个有序表则称为二路归并,同理,有三路归并、四路归并等。二路归并比较简单,所以我们只讨论二路归并。
例如有两个有序表: (7,10,13,15)和(4,8,19,20),归并后得到的有序表为: (4,7,8,10,13,15,19,20)。
归并过程为:比较A[i]和A[j]的大小,若A[i]≤A[j],则将第一个有序表中的元素A[i]复制到R[k]中,并令i和k分别加1,即使之分别指问后一单元,否则将第二个有序表中的元素A[j]复制到R[k]中,并令j和k分别加1;如此循环下去,直到其中的一个有序表取完,然后再将另一个有序表中剩余的元素复制到R中从下标k到下标t的单元.
void mergesort(int s,int t) //对[s,t]区间的无序数据进行归并排序 { int m,I,j,k; if (s==t) return; //若区间只有一个数据就不用排了 m = (s+t) / 2; //取区间的中点 mergesort(s,m); //以中点二分,对左边了区间进行排序 mergesort(m+1,t); //以中点二分,对右边了区间进行排序 i = s; //以下是一次归并(合并)操作 j = m+1; k = s; while (i<=m&&j<=t) do //二个子序列从小大到合并,直到有一列结束 { if (a[i]<=a[j] ) {r[k] = a[i]; i++; k++; } else { r[k] = a[j]; j++; k++;} end; while (i<=m) //把左边子序列剩余的元素接入进来 { r[k] = a[i]; i++; k++; } while (j<=t) //把右边子序列剩余的元素接入进来 { r[k] = a[j]; j++; k++; } for (i=s ;i<=t;i++) //把合并后的有序数据重新放回a数组 a[i] = r[i]; }