1. 程式人生 > >學習筆記-C語言5(演算法設計提高)

學習筆記-C語言5(演算法設計提高)

演算法複雜度是指演算法在編寫可執行程式後,執行時所需要的時間資源記憶體資源。演算法設計一般更在意時間和計算資源的開銷,而對空間資源則不太介意。

1. 二分查詢

二分查詢又稱折半查詢,首先陣列中的元素時按升序排列,將陣列中間位置的關鍵字與查詢關鍵字比較:

1)如果兩者相等,則查詢成功

2)否則利用中間位置將表分成前、後兩個子陣列:

  • 如果中間位置的關鍵字大於查詢關鍵字,則進一步查詢前一子陣列
  • 否則進一步查詢後一子陣列

重複以上過程,直到找到滿足條件的記錄,便查詢成功,或者直到字表不存在為止,此時查詢不成功。

二分查詢的時間複雜度log(n),整體時間複雜度nlog(n)。

實現程式碼:

普通迴圈版本:

int binary_search(int sort_array[],int n,int target){
	int begain=0;
	int end=n-1;
	while(end>=begin){
		int mid=(begain+end)/2;
		if(target==sort_array[mid]){
			return 1;
		}
		else if(target<sort_array[mid]){
			end=mid-1;
		}
		else if(target>sort_array[mid){
			begin=mid+1;
		}
	}
	return 0;
}

遞迴版本:

int binary_search(int sort_array[],int begain,int end,int target){
	if(end<begin){
		return 0;
	}
	int mid=(begain+end)/2;
	if(target==sort_array[mid]){
		return 1;
	}
	else if(target<sort_array[mid]){
		return binary_search(sort_array,begin,mid-1,target);
		}
	else if(target>sort_array[mid){
		return binary_search(sort_array,mid+1,end,target);
	}
}

2. LeetCode 34,Search for a Range(區間查詢)

題目描述:

給定一個排序陣列nums(nums中有重複元素)與目標值target,如果target在nums裡出現,則返回target所在區間的左右端點下標,[左端點,右端點],如果target在nums裡未出現,則返回[-1,-1]。

使用二分法分別求出左右端點的位置,程式碼如下:

//查詢左端點位置
int left_bound(int nums[],int n,int target){
	int begin =0;
	int end=n-1;
	while(begin<=end){
		int mid=(begain+end)/2;
		if (target==nums[mid]){
			if (nums[mid-1]<target || mid==0){
				return mid;
			}
			end=mid-1;
		}
		else if (target<nums[mid]){
			end=mid-1;
		}
		else if (target>nums[mid]){
			begin=mid+1;
		}		
	}
	return -1;
}
//查詢右端點位置
int right_bound(int nums[],int n,int target){
	int begin =0;
	int end=n-1;
	while(begin<=end){
		int mid=(begain+end)/2;
		if (target==nums[mid]){
			if (nums[mid+1]>target || mid==n-1){
				return mid;
			}
			begin=mid+1;
		}
		else if (target<nums[mid]){
			end=mid-1;
		}
		else if (target>nums[mid]){
			begin=mid+1;
		}		
	}
	return -1;
}

3. LeetCode 200. Number of Islands(島嶼數量)

題目描述:

用一個二維陣列代表一張地圖,這張地圖由字元“0”與字元“1”組成,其中“0”字元代表水域,“1”字元代表小島土地。小島“1”被水“0”所包圍,當小島土地“1”在水平和垂直方向相連線時,認為是同一塊土地。求這張地圖中小島的數量。如下圖分別是1和3個小島:

演算法分析:

第一步:

第二步:

一個完整的搜尋示意圖: 

完整程式碼實現:

遞迴深度搜索——小島數量

#include <stdio.h>
#include <stdlib.h>

#define MAXN 500
void DFS(int mark[][MAXN], char **grid,
		 int gridRowSize, int gridColSize,
		 int x, int y){
	mark[x][y] = 1;
	static const int dx[] = {-1, 1, 0, 0};
	static const int dy[] = {0, 0, -1, 1};
	int i;
	for (i = 0; i < 4; i++){
		int newx = dx[i] + x;
		int newy = dy[i] + y;
		if (newx < 0 || newx >= gridRowSize ||
			newy < 0 || newy >= gridColSize){
			continue;
		}
		if (mark[newx][newy] == 0 && grid[newx][newy] == '1'){
			DFS(mark, grid, gridRowSize, gridColSize, newx, newy);
		}
	}
}

int numIslands(char **grid, int gridRowSize, int gridColSize) {
    int island_num = 0;
    int mark[MAXN][MAXN] = {0};
    int i, j;
    for (i = 0; i < gridRowSize; i++){
   		for (j = 0; j < gridColSize; j++){
   			if (mark[i][j] == 0 && grid[i][j] == '1'){
    			DFS(mark, grid, gridRowSize, gridColSize, i, j);
	    		island_num++;
	    	}
    	}
    }
	return island_num;
}

int main(){
	char **grid;
	char str[10][10] = {"11100", "11000", "00100", "00011"};
	int i, j;
	grid = (char **)malloc(sizeof(char *) * 10);
	for (i = 0; i < 4; i++){
		grid[i] = (char *)malloc(sizeof(char) * 10);
		for (j = 0; j < 5; j++){
			grid[i][j] = str[i][j];
		}
	}
	printf("%d\n", numIslands(grid, 4, 5));
	for (i = 0; i < 10; i++){
		free(grid[i]);
	}
	free(grid);
	return 0;
}