排序
1 1.冒泡排序 2 时间复杂度:O(n²) 3 冒泡排序算法的运作如下:(从后往前) 4 1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。 5 2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。 6 3)针对所有的元素重复以上的步骤,除了最后一个。 7 4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 8 代码实现: 9 10 package cn.lpq.sort; 11 12 public class BubbleSort { 13 public static void main(String[] args) { 14 System.out.println("排序前:"); 15 int[] arr={51, 46, 20, 18, 65, 97, 82, 30, 77, 50,2,33,12,100 }; 16 printSort(arr); 17 System.out.println("排序后:"); 18 bubbleSort(arr); 19 printSort(arr); 20 21 } 22 public static void bubbleSort(int[]arr){ 23 for(int x=0;x<arr.length-1;x++){ 24 for(int y=0;y<arr.length-1-x;y++){ 25 if(arr[y]>arr[y+1]){ 26 int temp=arr[y]; 27 arr[y]=arr[y+1]; 28 arr[y+1]=temp; 29 } 30 } 31 32 } 33 } 34 public static void printSort(int []arr){ 35 StringBuilder res=new StringBuilder(); 36 res.append("["); 37 for(int i=0;i<arr.length;i++){ 38 if(i==arr.length-1) 39 res.append(arr[i]+"]"); 40 else 41 res.append(arr[i]+","); 42 } 43 System.out.println(res.toString()); 44 } 45 } 46 1 47 2 48 3 49 4 50 5 51 6 52 7 53 8 54 9 55 10 56 11 57 12 58 13 59 14 60 15 61 16 62 17 63 18 64 19 65 20 66 21 67 22 68 23 69 24 70 25 71 26 72 27 73 28 74 29 75 30 76 31 77 32 78 33 79 34 80 35 81 36 82 37 83 结果: 84 冒泡排序结果 85 2.选择排序: 86 时间复杂度:O(n²) 87 选择排序(Selection sort)同样也是最经典最简单的排序算法之一,特点就是简单直观。 88 排序的原理:首先在未排序的序列里找到最小(大)元素,放到序列的首端,再从剩余元素中找到最小(大)的元素,放到序列的尾端。依次循环,直到排序完成。 89 代码实现: 90 91 package cn.lpq.sort; 92 93 public class SelectSort { 94 public static void main(String[] args) { 95 int[] arr={11,9,3,44,12,98,292,34,522,232}; 96 System.out.println("选择排序前:"); 97 printSort(arr); 98 selectSort(arr); 99 System.out.println("选择排序后:"); 100 printSort(arr); 101 } 102 public static void selectSort(int[]arr){ 103 for(int x=0;x<arr.length-1;x++){ 104 for(int y=x+1;y<arr.length;y++){ 105 if(arr[x]>arr[y]){ 106 int temp=arr[y]; 107 arr[y]=arr[x]; 108 arr[x]=temp; 109 110 } 111 } 112 113 } 114 } 115 public static void printSort(int []arr){ 116 StringBuilder res=new StringBuilder(); 117 res.append("["); 118 for(int i=0;i<arr.length;i++){ 119 if(i==arr.length-1) 120 res.append(arr[i]+"]"); 121 else 122 res.append(arr[i]+","); 123 } 124 System.out.println(res.toString()); 125 } 126 } 127 1 128 2 129 3 130 4 131 5 132 6 133 7 134 8 135 9 136 10 137 11 138 12 139 13 140 14 141 15 142 16 143 17 144 18 145 19 146 20 147 21 148 22 149 23 150 24 151 25 152 26 153 27 154 28 155 29 156 30 157 31 158 32 159 33 160 34 161 35 162 36 163 37 164 结果: 165 选择排序结果 166 167 3.快速排序: 168 快排思想: 169 快速排序的原理:选择一个关键值作为基准值。比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一般是无序的)。一般选择序列的第一个元素。 170 一次循环:从后往前比较,用基准值和最后一个值比较,如果比基准值小的交换位置,如果没有继续比较下一个,直到找到第一个比基准值小的值才交换。找到这个值之后,又从前往后开始比较,如果有比基准值大的,交换位置,如果没有继续比较下一个,直到找到第一个比基准值大的值才交换。直到从前往后的比较索引>从后往前比较的索引,结束第一次循环,此时,对于基准值来说,左右两边就是有序的了,接着分别比较左右两边的序列,重复上述的循环。 171 时间复杂度为:nlog(n) 172 173 package cn.dataStructures.Sort; 174 //快速排序算法--利用递归 175 public class QuickSort { 176 public static void main(String[] args) { 177 int []arr={12,20,5,16,15,1,2,100,30,45,23,9}; 178 int low=0; 179 int high=arr.length-1; 180 quickSort(arr,low,high); 181 printSortArr(arr); 182 } 183 public static void quickSort(int [] arr,int low,int high){ 184 int start=low;//设置可以移动的最小值 185 int end=high;//设置可以移动的最大值 186 int key=arr[low];//设置标识 187 while(start<end){//整体大循环 188 while(start<end&&arr[end]>=key)//先从循环后面的,从后向前,找小于key的 189 end--; 190 if(arr[end]<=key){ 191 int temp=arr[end]; 192 arr[end]=arr[start]; 193 arr[start]=temp; 194 } 195 while(start<end&&arr[start]<=key)//循环前面的,从前往后找大于key的值 196 start++; 197 if(arr[start]>=key){ 198 int temp=arr[start]; 199 arr[start]=arr[end]; 200 arr[end]=temp; 201 } 202 } 203 //递归调用 204 if(low<start) 205 quickSort(arr,low,start-1); 206 if(end<high) 207 quickSort(arr,end+1,high); 208 209 }//打印输出数组 210 public static void printSortArr(int []arr){ 211 StringBuilder res=new StringBuilder(); 212 res.append("["); 213 for(int i=0;i<arr.length;i++){ 214 if(i==arr.length-1){ 215 res.append(arr[i]+"]"); 216 } 217 else{ 218 res.append(arr[i]+","); 219 } 220 } 221 System.out.println(res.toString()); 222 } 223 } 224 1 225 2 226 3 227 4 228 5 229 6 230 7 231 8 232 9 233 10 234 11 235 12 236 13 237 14 238 15 239 16 240 17 241 18 242 19 243 20 244 21 245 22 246 23 247 24 248 25 249 26 250 27 251 28 252 29 253 30 254 31 255 32 256 33 257 34 258 35 259 36 260 37 261 38 262 39 263 40 264 41 265 42 266 43 267 44 268 45 269 46 270 47 271 48 272 49 273 50 274 51 275 52 276 结果: 277 快速排序结果 278 4.归并排序: 279 时间复杂度为:nlog(n) 280 排序原理: 281 (1)申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 282 (2)设定两个指针,最初位置分别为两个已经排序序列的起始位置 283 (3)比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置 284 (4)重复步骤3直到某一指针达到序列尾 285 (5)将另一序列剩下的所有元素直接复制到合并序列尾 286 287 package cn.dataStructures.Sort; 288 289 /** 290 * **归并排序(理解描述)**: 291 * 思想: 292 * 1.对原始序列arr进行一半分割,设置原始序列的第一个索引low和最后一个索引值high,并创建临时序列 293 * 2.求出原始序列的中间索引mid=(low+high)/2,根据mid对序列分割 294 * 3.判断low是否小于high,满足则递归调用步骤1和2,一直对分割的序列再分割,直到剩余一个元素为止 295 * 4.对分割的序列分别根据其索引指向的元素值进行比较,小的则放入临时序列中,各序列索引加1、、 296 * 5.对剩余没有加入到临时序列中的元素直接添加到临时序列的最后的位置 297 * 6.将临时序列赋值给原始序列,此时原始序列就是已经排好序的序列 298 * @author lpq 299 * 300 */ 301 302 public class MergeSort { 303 public static void main(String[] args) { 304 System.out.println("排序前:"); 305 int[] arr={51, 46, 20, 18, 65, 97, 82, 30, 77, 50 }; 306 printSort(arr); 307 mergeSort(arr,0,arr.length-1); 308 System.out.println("排序后:"); 309 printSort(arr); 310 } 311 //切分原始数组 312 public static void mergeSort(int[]arr,int low,int high){ 313 int mid=(low+high)/2;//将序列按中间分开 314 315 if(low<high){ 316 //分开左边 317 mergeSort(arr,low,mid); 318 //右半边 319 mergeSort(arr,mid+1,high); 320 //将左右已经排序好的合并 321 merge(arr,low,mid,high); 322 } 323 324 325 } 326 public static void merge(int[]arr,int low,int mid,int high){ 327 /** 328 * 这里的start和end分别是左半边序列和右半边序列的其实指针,分别指向各半边序列的第一个位置,随着的元素的比较而发生改变 329 * 而low和high是不发生改变的,一般来说low指的是序列的第一个索引0即low=0,high=arr.lenth-1, 330 * low和length值不发生改变 331 */ 332 //临时数组(序列) 333 int [] temp=new int[high-low+1]; 334 //左半边序列的指针(一般指向第一个位置low) 335 int start=low; 336 //右半边序列的指针 337 int end=mid+1; 338 //临时数组序列的索引 339 int k=0; 340 //把小的元素加入到临时数组中 341 while(start<=mid&&end<=high){ 342 if(arr[start]<arr[end]) 343 temp[k++]=arr[start++]; 344 else 345 temp[k++]=arr[end++]; 346 } 347 //把左边剩余元素加入到临时数组的后面 348 while(start<=mid)//这里不能用if判断,因为if只能判断一次,while只要满足条件就会一直循环判断下去 349 temp[k++]=arr[start++]; 350 //把右半边剩余元素加入到临时数组的后面 351 while(end<=high) 352 temp[k++]=arr[end++]; 353 //将排序好的临时数组复制给原始数组arr 354 for(int i=0;i<temp.length;i++){ 355 arr[i+low]=temp[i]; 356 } 357 } 358 public static void printSort(int []arr){ 359 StringBuilder res=new StringBuilder(); 360 res.append("["); 361 for(int i=0;i<arr.length;i++){ 362 if(i==arr.length-1) 363 res.append(arr[i]+"]"); 364 else 365 res.append(arr[i]+","); 366 } 367 System.out.println(res.toString()); 368 } 369 } 370 371 1 372 2 373 3 374 4 375 5 376 6 377 7 378 8 379 9 380 10 381 11 382 12 383 13 384 14 385 15 386 16 387 17 388 18 389 19 390 20 391 21 392 22 393 23 394 24 395 25 396 26 397 27 398 28 399 29 400 30 401 31 402 32 403 33 404 34 405 35 406 36 407 37 408 38 409 39 410 40 411 41 412 42 413 43 414 44 415 45 416 46 417 47 418 48 419 49 420 50 421 51 422 52 423 53 424 54 425 55 426 56 427 57 428 58 429 59 430 60 431 61 432 62 433 63 434 64 435 65 436 66 437 67 438 68 439 69 440 70 441 71 442 72 443 73 444 74 445 75 446 76 447 77 448 78 449 79 450 80 451 81 452 82 453 83 454 84 455 85 456 结果: 457 归并排序结果 458 时间复杂度分析: 459 递归法分析: 460 因为归并排序实现要将原始序列分为2部分,然后将这2个序列排序好后再赋值给临时序列temp,假设原始序列的元素个数为N,则时间复杂度的主要表达式为:T(N)=2T(N/2)+N; 461 1.首先将N/2带入主要表达式。结果:2T(N/2)=2(2T(N/4))+N=4T(N/4)+N,根据主要表达式可知:2T(N/2)=T(N)-N,所以可简化为:T(N)=4T(N/4)+2N 462 2.将N/4带入主表达式,同理可得到:T(N)=8T(N/8)+3N,可类比为:T(N)=2^kT(N/2^k)+kN 463 3.利用k=log(N),可得T(N)=NT(1)+Nlog(N)=Nlog(N)+N 464 4.时间复杂度为:O(Nlog(N)) 465 二分搜索法: 466 二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。 467 注意:二分查找前提条件是:该序列有序 468 469 package cn.lpq.sort; 470 471 import java.util.Arrays; 472 473 //二分查找前提是该数组有序 474 public class BinarySerch { 475 public static void main(String[] args) { 476 int []arr={11,22,33,44,55,66,77}; 477 Arrays.sort(arr);//对数组排序 478 System.out.println(binarySerch(arr,55)); 479 } 480 public static int binarySerch(int[]arr,int value){ 481 int min=0; 482 int max=arr.length-1; 483 int mid=(min+max)/2; 484 while(arr[mid]!=value){ 485 if(arr[mid]>value){ 486 max=mid-1; 487 } 488 else if(arr[mid]<value){ 489 min=mid+1; 490 } 491 mid=(min+max)/2; 492 } 493 if(min>max){ 494 return -1;//说明数组为空或所查找元素不存在 495 } 496 return mid; 497 498 } 499 }