Datawhale 系列數據結構
Task3.1 排序
3.1.1歸併
//採用分治(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全的序列
public static int [] mergeSort(int []arr){
int len =arr.length;
if(len<2){
return arr;
}
int [] left=Arrays.copyOfRange(arr,0,len/2);
int [] right=Arrays.copyOfRange(arr,len/2,len);
return merge(mergeSort(left),mergeSort(right));
}
public static int [] merge(int [] left,int [] right){
int llen=left.length;
int rlen=right.length;
int[] res=new int[llen+rlen];
int li=0,ri=0,rei=0;
while (llen-li>0 && rlen-ri>0) {
if (left[li] <= right[ri]) {
res[rei++]=left[li++];
} else {
res[rei++]=right[ri++];
}
}
while (llen-li>0) {
res[rei++]=left[li++];
}
while (rlen-ri>0) {
res[rei++]=right[ri++];
}
return res;
}
3.1.2 快速排序
/*快速排序使用分治法來把一個list分爲兩個子list:
*從數列中跳出一個元素,稱爲“基準”(pivot)
*重新排序數列,所有元素比基準小的擺放在基準前面,所有比基準大的放在基準後面。在這個分區推出後,該基準就處於數列的中間位置。這個稱爲分區操作。
*遞歸的,把小於基準值元素的子數列和大於基準值元素的子數列排序
*/
public static int partition(int []array,int lo,int hi){
//固定的切分方式
int key=array[lo];
while(lo<hi){
while(array[hi]>=key&&hi>lo){//從後半部分向前掃描
hi--;
}
array[lo]=array[hi];
while(array[lo]<=key&&hi>lo){從前半部分向後掃描
lo++;
}
array[hi]=array[lo];
}
array[hi]=key;
return hi;
}
public static void sort(int[] array,int lo ,int hi){
if(lo>=hi){
return ;
}
int index=partition(array,lo,hi);
sort(array,lo,index-1);
sort(array,index+1,hi);
}
3.1.3 插入
public static int [] insertionSort(int []arr){
for(int i=0;i<arr.length;i++){
for(int j=i;j>0;j--){
if(arr[j]<arr[j-1]){
int temp=arr[j];
arr[j]=arr[j-1];
arr[j-1]=temp;
}
}
}
return arr;
}
3.1.4 冒泡
public static int [] bubbleSort(int [] arr){
for(int i= 0;i<arr.length-1;i++){
for(int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
int temp =arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
return arr;
}
3.1.5 選擇
public static int [] selectionSort(int [] arr){
int min = 0;
for(int i=0;i<arr.length-1;i++){
for(int j=i+1;j<arr.length-1;j++){
min = arr[i];
if(arr[j]<min){
min=arr[j];
arr[j]=arr[i];
arr[i]=min;
}
}
}
return arr;
}
3.1.6 堆排序(選做)
/*堆排序分爲三個步驟:
* 創建最大堆
* 確保最大堆中父節點的值比子節點的值都大
* 將根節點與最後一個葉子節點比較,擇其大者剔除出堆,再重複第2、3步。
*第二步是整個堆排序的關鍵。
*/
public static void maxHeapify(int[] array, int heapsize, int i){
int l = 2*i + 1;
int r = 2*i + 2;
int large = i;
if (l < heapsize && array[i] < array[l]) {
large = l;
}else {
large = i;
}
if (r < heapsize && array[large] < array[r]) {
large = r;
}
if (large != i) {
int temp = array[i];
array[i] = array[large];
array[large] = temp;
//因爲將最大值和父節點交換了位置,新的子節點並不能保證一定是比它的子節點大
//所以需要遞歸,確定交換的子節點比它的子節點都大
//而沒有動的子節點是不需要進行遞歸的,因爲它的數值沒有變,如果之前滿足最大堆條件,現在就還是滿足的
maxHeapify(array, heapsize, large);
}
}
//創建堆
public static void buildMaxHeap(int[] array){
int heapsize = array.length;
for (int i = heapsize/2; i >= 0; i--) {
maxHeapify(array,heapsize,i);
}
}
public static void heapSort(int[] array){
int heapsize = array.length;
for (int i = heapsize - 1; i > 0; i--) {
if (array[i] < array[0]) {
int temp = array[0];
array[0] = array[i];
array[i] = temp;
heapsize --;
maxHeapify(array, heapsize, 0);
}
}
}
3.1.8 編程實現 O(n) 時間複雜度內找到一組數據第 K 大元素
//採用堆排序的方法
//在創建最小堆,只創建K個元素
public static void maxHeapify(int[] array, int size, int i) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int small = i;
if (left < size) {
if (array[small] > array[left]) {
small = left;
}
}
if (right < size) {
if (array[small] > array[right]) {
small = right;
}
}
if (small != i) {
int temp = array[small];
array[small] = array[i];
array[i] = temp;
maxHeapify(array, size, small);
}
}
public static void buildHeap(int[] array, int size) {
for (int i = size - 1; i >= 0; i--) {
maxHeapify(array, size, i);
}
}
public static int findKByHeap(int[] array, int k) {
buildHeap(array, k);
for (int i = k + 1; i < array.length; i++) {
if (array[i] > array[0]) {
int temp = array[i];
array[i] = array[0];
array[0] = temp;
maxHeapify(array, k, 0);
}
}
return array[0];
}
TASK3.2 查找
3.2.1 實現一個有序數組的二分查找
//默認數組是有序數組
public static int biSearch(int [] arr, int target){
int r = arr.length-1;
int l = 0;
int mid=r/2;
while(l<=r){
mid=(l+r)/2;
if(arr[mid]==target)
return mid;
else if(arr[mid]>target)
r=mid;
else
l=mid;
}
return -1;
}
3.2.2 實現模糊二分查找算法(比如大於等於給定值的第一個元素)
//模糊二分查找,返回大於等於給定值的第一個值的下標
public static int blurrySearch(int [] arr, int target){
int r = arr.length-1;
int l = 0;
int mid=r/2;
while(l<=r){
mid=(l+r)/2;
if(arr[mid]==target)
return mid;
else if(arr[mid]>target)
r=mid-1;
else
l=mid+1;
}
return r+1;
}
3.2.3 Sqrt(x)(x的平方根)
class Solution {
public int mySqrt(int x) {
if(x==1) return 1;
int min=0;
int max = x;
while(max-min>1){
int m=(max+min)/2;
if(x/m<m) max=m;
else min = m;
}
return min;
}
}