1. 程式人生 > 實用技巧 >P1712 [NOI2016]區間

P1712 [NOI2016]區間

  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 }