1 /************
2 十大排序算法
3 ***********/
4
5 #include<iostream>
6 #include<ctime>
7 using namespace std;
8
9 typedef int T;
10
11 void swap(T &x,T &y)
12 {
13 T temp;
14 temp=x;
15 x=y;
16 y=temp;
17 }
18 //1,冒泡 原地稳定 o(n^2)
19 void bubble(T *a, int n)
20 {
21 for(int i=0;i<n-1;i++)
22 for(int j=0;j<n-1-i;j++)
23 {
24 if(a[j]>a[j+1])
25 swap(a[j],a[j+1]);
26 }
27 }
28
29 void improvebubble(T *a, int n)
30 {
31 bool over=true;//作指示,若有一次没交换就结束
32 for(int i=0;i<n-1&&over;i++)
33 {
34 over =false;
35 for(int j=0;j<n-1-i;j++)
36 if(a[j]>a[j+1])
37 {
38 swap(a[j],a[j+1]);
39 over=true;
40 }
41 }
42 }
43 //2,插排 原地稳定 o(T)=1+2+3+..+n-1=o(n^2)
44 void insert1(T *a,int n)
45 {
46 for(int i=1;i<n;i++)
47 {
48 T temp=a[i];
49 int j;
50 for(j=i-1;j>=0;j--)//和前面抽出来有序的比较
51 {
52 if(a[j]<=temp)
53 break;
54 a[j+1]=a[j];
55 }
56 a[j]=temp;
57 }
58 }
59
60 int findpos(T *a,int n, T key)
61 {
62 int high=n-1,low=0;
63 while(low<=high)//***这里要有等号,不然high=low(即排查到只剩一个数时)就不判断直接排在前面了
64 {
65 int mid=(high+low)/2;
66 if(key>=a[mid]) //如果相等,定位到其后面,保证稳定排序
67 low=mid+1;
68 else if (key<a[mid])
69 high=mid-1;
70 }
71
72 return low;
73 }
74 void insert2(T *a,int n)
75 {
76 for(int i=1;i<n;i++)
77 {
78 T temp=a[i];
79 int pos=findpos(a,i,temp);
80 for(int j=i-1;j>=pos;j--)
81 {
82 a[j+1]=a[j];
83 }
84 a[pos]=temp;
85 cout<<pos<<endl;
86 for(int i=0;i<n;i++)
87 cout<<a[i];
88 cout<<endl;
89 }
90 }
91
92
93 //3,选择排序 原地不稳定,一次选一个最小的, o(n^2)
94 void select(T *a,int n)
95 {
96 for(int i=0;i<n-1;i++)
97 {
98 T min=a[i];
99 int k=i;//重要一定要让k=i
100 for(int j=i+1;j<n;j++)
101 {
102 if(min>a[j])//找最小的
103 {
104 min=a[j];
105 k=j;
106 }
107 }
108 if(i!=k)//重要
109 swap(a[i],a[k]);//不稳定,比如a[i]不是最小的,它与最小发生交换,打乱了它自己的位置
110
111 }
112 }
113 //4.归并排序 非原地稳定 o(nlogn), 需要开辟o(n)的空间
114 //分治法,每次一分为二,最后将俩部分合并排序
115 void MergeSort(T *a,int f,int r,int mid)
116 {
117 int i=f,j=mid+1;
118 int m=mid,n=r;
119 int k=0;
120 T *temp=new T[r-f+1];//非原地排序,用来合并数组
121
122 while(i<=m && j<=n)
123 {
124 if(a[i]<=a[j])//这里等号可保证稳定
125 temp[k++]=a[i++];
126 else
127 temp[k++]=a[j++];
128 }
129 while(i<=m)
130 temp[k++]=a[i++];
131 while(j<=n)
132 temp[k++]=a[j++];
133 for(i=0;i<k;i++)//数组a局部有序
134 a[f+i]=temp[i];
135
136 delete [] temp;
137 }
138
139 void Merge(T *a,int f,int r)
140 {
141 if(f<r)
142 {
143 int mid=(f+r)/2;
144 Merge(a,f,mid);
145 Merge(a,mid+1,r);
146 MergeSort(a,f,r,mid);
147 }
148 }
149 void merge(T *a, int n)
150 {
151 Merge(a,0,n-1);
152 }
153
154 //5.快排,原地不稳定 o(nlogn)
155 void Quick(T *a,int f,int r)
156 {
157 if(f>=r)
158 return;
159 int i=f,j=r;
160 T temp=a[f];//第一个坑
161 while(i<j)
162 {
163 while(temp<=a[j] && i<j)//有可能越界
164 j--;
165 if(i<j)//如果俩者相遇,即跑到挖的坑那了
166 a[i++]=a[j];//后面的小的数填前面的坑
167 while(temp>a[i] && i<j)
168 i++;
169 if(i<j)
170 a[j--]=a[i];//用前面的大的数填后面的坑
171 }
172 a[i]=temp;//最后一坑
173 Quick(a,f,i);
174 Quick(a,i+1,r);
175 }
176 void quick(T*a,int n)
177 {
178 Quick(a,0,n-1);
179 }
180
181 //6.计数排序
182 //只能是整数(或字符)排序,而且要求分布比较均匀,非原地稳定
183 //好处是o(n)线性复杂度,方便序列去重操作
184 void count(T *a,int n)
185 {
186 T max=a[0],min=a[0];
187 int i;
188 for(i=0;i<n;i++)//找到序列最小值,以确定桶大小
189 {
190 if(max<a[i])
191 max=a[i];
192 if(min>a[i])
193 min=a[i];
194 }
195 int len=max-min+1;
196 T* C=new T[len];//记录每个数出现的次数
197 for(i=0;i<len;i++)
198 C[i]=0;
199 for(i=0;i<n;i++)
200 C[a[i]-min]+=1;
201 for(i=1;i<len;i++)
202 C[i]+=C[i-1];
203
204 T *R=new T[n];//
205 for(i=n-1;i>=0;i--)//倒着来取可保证稳定排序,后面的还排在后面
206 {
207 T temp=a[i];
208 int pos=C[temp-min];
209 R[pos-1]=temp;//注意这的减一.C统计的的是个数,R是从0开始存储的
210 C[temp-min]--;
211 }
212
213 for(i=0;i<n;i++)
214 a[i]=R[i];
215
216 delete [] C;
217 delete [] R;
218 }
219 //7,希尔排序 分组排序 原地不稳定
220 //数组基本有序的情况下更好
221 void shell1(T *a, int n)
222 {
223 for(int gap=n/2;gap>0;gap/=2) //log n
224 for(int i=gap;i<n;i++)//gap=1就是insertSort o(n/gap)
225 for(int j=i-gap;j>=0 && a[j]>a[j+gap];j-=gap)
226 swap(a[j+gap],a[j]);//或者可以先后推找到位置,最后填进去
227 }
228
229 void shell2(T *a,int n)//??不理解 o(nlogn)
230 {
231 int d=n;
232 while(d>1)
233 {
234 d=(d+1)/2;
235 for(int i=0;i<n-d;i++)
236 if(a[i+d]<a[i])
237 swap(a[i+d],a[i]);
238 }
239 }
240
241
242 //8,堆排序 大根堆,向下调整 o(nlogn) 原地不稳定 适合处理大文件
243 void shiftdown(T *a,int n,int i)//
244 {
245 int t,flag=0;
246 while(2*i+1<n && flag==0)//以0为根节点,左右孩子是2i+1,2i+2
247 {
248 if(a[i]<a[2*i+1])
249 t=2*i+1;
250 else t=i;
251 if(2*i+2<n)//n是节点数,从1开始计的,而i是从0开始计的
252 if(a[t]<a[2*i+2])
253 t=2*i+2;
254 if(t!=i)
255 {
256 swap(a[i],a[t]);
257 i=t;//继续往下调整
258 }
259 else flag=1;
260 }
261 }
262
263 void createMaxHeap(T *a,int n)//建立大根堆,o(n/2)
264 {
265 for(int i=n/2;i>=0;i--)//父节点向下调整
266 shiftdown(a,n,i);
267 }
268
269 void heapsort(T *a, int n)
270 {
271 createMaxHeap(a,n);
272 int k=n-1;
273 while(k>0)
274 {
275 swap(a[k],a[0]);
276 k--;
277 shiftdown(a,k,0);//o(logk)
278 }
279 }
280
281 int main()
282 {
283 const int n=15;
284 int a[n]={4,6,5,3,2,1,4,5,6,7,2,8,9,3,1};
285 shell2(a,n);
286 for(int i=0;i<n;i++)
287 cout<<a[i];
288 cout<<endl;
289 return 0;
290 }