【算法基礎個人常用總結】

很多東西久不用了,原本再熟悉也是會忘記的,現在可算是體會到了,記錄下來常用的基礎知識,方便日後再撿起來,加油。

<-------持續更新------->
<-------持續更新------->
<-------持續更新------->

一個正在努力的小夥子

# 二叉樹,節點指針數據類型,先序遍歷,中序遍歷(加一個路徑棧記錄往L還是往R擴展,方便手工畫出二叉樹)

/**
1)
二叉樹結構:
			node0
		   /	 \
	   node1      node2
      /    \     /     \
  node3  node4  node5  node6
  /  \   /   \  /  \   /   \
NULL N	N	N	N	N  N	N	

2) ******* 關鍵 *******
把
			node0
		   /	 \
看成一個單元,則根節點,樹節點,葉節點,都統一起來了。

3)
插入第一個元素前
			NULL
插入第一個元素後
			node0
		   /	 \
*/

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

struct Node {
	int data;
	Node* l;
	Node* r;
};

void insert(Node* &root, Node* node) {
	// Node* &root, 要改變root自身的值必須&引用數據類型 
	// Node* node,  要改變的是node指針指向的值,例如node->data的值,則直接Node* 即可
	if (root == NULL) {
		root = node;
		return;
	}
	if (node->data <= root->data) {		
		insert(root->l, node);
	} else {
		insert(root->r, node);
	}
}
// 先序遍歷: l, M, R
void showTree(Node* root){
	if (root == NULL) return;
	showTree(root->l);
	printf("%d ", root->data);
	showTree(root->r);
}

// 中序遍歷: M, L, R
// 加一個路徑記錄是擴展左還是右節點,方便畫出二叉樹
void showTree2(Node* root, char path[], int pi){
	if (root == NULL) return;
	printf("%d# ", pi);
	for (int i = 0; i < pi; i++) {
		printf("%c ", path[i]);
	}
	printf("%d \n", root->data);
	
	path[pi++] = 'L';
	showTree2(root->l, path, pi);
	pi--;
	path[pi++] = 'R';
	showTree2(root->r, path, pi);
	pi--;
}

int main() {	
	int i, n;
	n = 20;
	Node* root = NULL;
	// add elements
	for (i = 0; i < n; i++) {
		int data = rand() % n;
		printf("%d ", data);
		Node* node = (Node*)malloc(sizeof(Node)); // 動態分配空間,相當於new一個對象
		node->data = data;
		node->l = NULL;
		node->r = NULL;
		insert(root, node);
	}
	printf("\n");
	
	// show the tree
	char path[40];
	int pi = 0;
	showTree(root);
	printf("\n");
	showTree2(root, path, pi);
	return 0;
}

#


# 二分搜索

#include<stdio.h>

int bSearch(int a[], int l, int r, int key) {
	int mid;
	while (l <= r) {
		mid = (l + r) >> 1;
		if (key == a[mid]) return mid;
		if (key < a[mid]) {
			r = mid - 1;		
		} else {
			l = mid + 1;
		}
	}
	return -1;
}

int main() {
	int a[1024];
	int i, n;
	n = 1024;
	for (i = 0; i < n; i++) {
		a[i] = i;
	}
	int key = 7;
	int index = bSearch(a, 0, n - 1, key);
	printf("index = %d\n", index);
	return 0;
}

#


# 常用數據結構,priority_queue的常用功能,優先隊列,一次查找時間複雜度爲logN, 前k大數

#include<stdio.h>
#include<queue>
#include<vector>
#include<stdlib.h>
using namespace std;

struct Node {
	int x;
	int y;
};

struct cmp {
	bool operator()(const Node n1, const Node n2) {
		if (n1.x != n2.x) {
			return n1.x > n2.x; // ascending by x 
		} else {
			return n2.y > n2.y; // ascending by y when n1.x == n2.x
		}
	}
};

priority_queue<Node, vector<Node>, cmp> myQueue;

int main() {
	int i, n;
	n = 10;
	// add elements
	for (i = 0; i < n; i++) {
		int x = rand() % n;
		int y = rand() % n;
		printf("%d,%d  ", x, y);
		Node node;
		node.x = x;
		node.y = y;
		myQueue.push(node);
	}
	printf("\n");

	// print all elements
	while (!myQueue.empty()) {
		Node node = myQueue.top();
		myQueue.pop();

		printf("%d,%d  ", node.x, node.y);
	}
	printf("\n");

	return 0;
}

#

# 更新priority_queue

#include<stdio.h>
#include<vector>
#include<queue>
using namespace std;

struct Node {
  int x;  
};
struct cmp{
    bool operator()(const Node* n1, const Node* n2) {
        return n1->x >= n2->x;
    }
};
int main() {
	priority_queue<Node*, vector<Node*>, cmp> myQueue;
	Node* node1 = (Node*)malloc(sizeof(Node));
	Node* node2 = (Node*)malloc(sizeof(Node));
	Node* node3 = (Node*)malloc(sizeof(Node));
	node1->x = 1;
	node2->x = 2;
	node3->x = 3;
	node2->x = 2222222; // delete
	
	// dynamic update
	Node* tmp = myQueue.top();
    myQueue.pop();
    myQueue.push(tmp);

	return 0;
}

#

# 常用數據結構,map的常用功能,hash功能,打表,下標離散不連續,且個數也是未知的

#include<stdio.h>
#include<map>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<iostream>
using namespace std;

struct cmp {
	bool operator()(const int x1, const int x2) {
		return x1 > x2;
	}
};

map<int, int> m1;
map<int, string> m2;
map<string, int> m3;

int main() {
	int i, n;
	n = 10;
// <int, int>
	// add elements
	for (i = 0; i < n; i++) {
		int key = i;
		m1[key] = i + 100;
	}
	// delete elements in m
	m1.erase(1); // by key
	
	// upper_bound, << key < 返回的下標的指針
	printf("upper_bound = %d\n", *m1.upper_bound(3)); // 1, 2, 3, 3, 3, 3, 3, 4  @ 返回的是最後一個3的下標 + 1
	// lower_boudd, < key <= 返回的下標的指針 
	printf("lower_bound = %d\n", *m1.lower_bound(3)); // 1, 2, 3, 3, 3, 3, 3, 4  @ 返回的是第一個3的下標

	// juedging whether m contains a key
	int key = 77;
	if (m1.count(key) != 0) {
		printf("m1 contains %d\n", key);
	} else {
		printf("m1 doesn't contain %d\n", key);
	}

	// travel all elements, which is sorted by key in m1
	map<int,int>::iterator it1;
	for (it1 =  m1.begin(); it1 != m1.end(); it1++) {
		printf("m[%d]=%d ", it1->first, it1->second);
	} printf("\n");

// <int, string>
	// char[] 可以當string用,但是string不能能char[]用
	char cs[] = "charArrayString";
	m2[1] = cs;
	// printf("%s\n", m2[1]); // Runtime Error, 因爲m2[1]拿到的是string類型,不是char[]類型
	cout << m2[1] << endl; // use cout to print string
	for (i = 0; i < m2[1].size(); i++) {
		printf("%c", m2[1].at(i));
	} printf("\n");

// <string, int>
	char cs2[] = "bbb";
	m3[cs2] = 222;
	printf("cs[], %d\n", m3["bbb"]); // char[] can auto convert to string
	string str2 = "bbb";
	printf("string, %d\n", m3[str2]);


<span style="white-space:pre">	</span>printf("========== m customed sort\n");
	map<int, int, cmp> m; // m不能使用erase
	m[2] = 22;
	m[3] = 33;
	m[1] = 11;
	map<int, int, cmp>::iterator it;
	for (it = m.begin(); it != m.end(); it++) {
		printf("%d,%d ", it->first, it->second);
	}
	return 0;
}

#


# 常用數據結構,vector的常用,鏈表功能,主要是數組長度不固定

#include<stdio.h>
#include<vector>
using namespace std;

struct Node {
	int x;
	int y;
};

vector<int> list1;
vector<Node> list2;

int main() {
	int i, n;
	n = 10;
	// 初始化
	list1.clear();
	
	// 添加元素
	for (i = 0; i < n; i++) {
		list1.push_back(i);
	}

	// 在第k個位置插入一個值
	int k = 0;
	vector<int>::iterator it = list1.begin() + k; // +  被重載了
	list1.insert(it, -1);

	// 刪除元素
	list1.erase(it); // it是指針參數
	// list1.erase(list1.end() - 1); // list1.pop_back(); // 刪除最後一個元素,兩個等價

	// 遍歷
	int len1 = list1.size();
	for (i = 0; i < len1; i++) {
		printf("%d ", list1[i]);
		// list1[i] 等價 list1.at(i))
	}
	printf("\n");

	// 自定義數據類型
	for (i = 0; i < n; i++) {
		Node node;
		node.x = i;
		node.y = 2 * i;
		list2.push_back(node);
	}
	int len2 = list2.size();
	for (i = 0; i < len2; i++) {
		printf("%d,%d ", list2[i].x, list2[i].y);
	}
	printf("\n");
	return 0;
}

#


# 計時,打印時間

#include<stdio.h>
#include<time.h>

int main() {
	clock_t t1 = clock();

	int i, n;
	n = 1e9;
	int sum = 1;
	for (i = 0; i < n; i++) {
		sum = sum + i;
	}

	clock_t t2 = clock();
	printf("time = %d\n", t2 - t1);
	return 0;
}

#


# 讀入字符串:1》按空格、回車等分隔讀字符串,2》 讀整行字符串(包括空格)

#include<stdio.h>
#include<string.h>
#include<string>

char str[100];

int main() {
	int i, n;	
	scanf("%d", &n);
	printf("n = %d\n", n);

	for (i = 0; i < n; i++) {
		scanf("%s", str); // 讀字符串,以空格,製表符,回車等爲分界線
		printf("%s\n", str);
		printf("length = %d\n", strlen(str));
	}
	
	getchar(); // 如果再gets之前用過scanf,那麼在gets之前需要getchar把當前行的回車吸收掉,到下一行
	gets(str); // 讀一整行,包括空格
	printf("%s", str);
	return 0;
}

#


# 讀文件,寫文件,和控制檯IO的切換

#include<stdio.h>

char str[100];

int main() {
	// file
	freopen("in.txt", "r", stdin);
	scanf("%s", &str);
	freopen("out.txt", "w", stdout);
	printf("%s", str);
	
	// console
	freopen("con", "r", stdin);
	scanf("%s", &str);
	freopen("con", "w", stdout);
	printf("%s", str);
	return 0;
}

#

# 完全copy一個文件,包括空行,空格,回車,全部一樣

#include<stdio.h>

char str[100];

int main() {
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
	int flag = 0;
	while(gets(str) != NULL) { // gets一次讀一行,會把空行,空格都會讀進來,
		if (flag++ > 0) printf("\n");
		printf("%s", str);
	}
	return 0;
}

#


# 浮點數問題,四捨五入,double不用==,double用作差絕對值絕對值,浮點數絕對值fabs

#include<stdio.h>
#include<math.h>
int main() {
	double d1 = 7.00000000001;
	double d2 = 6.9999999;

	int d1Int = (int)(d1 + 0.5); // 四捨五入
	int d2Int = (int)(d2 + 0.5);
	
	printf("%.15f %d\n", d1, d1Int); // %f只保留6位,
	printf("%f %d\n", d2, d2Int);
	
	// fabs浮點數絕對值
	if (fabs(d1 - d1Int) < 1e-6) { //1e-6 = 0.000001, double不能用==,應該用絕對值小於一個足夠小的數
		printf("777\n");
	}
	return 0;
}

#

# 取對數精度問題

// e = (int)log5(n)

#include<stdio.h>
#include<math.h>

int main() {
	int n1 = 625;
	int n2 = 626;
	int n = n1;
	//
	double d1 = log(n) / log(5);
	int i1 = d1;
	printf("%d\n", i1); // 3 wrong answer
	

	// n1 ~= n2, e1 == e2
	// so we compare n1 and n2
	_int64 ni = 1;
	int ei = -1;
	while (ni <= n) { // find the first ni > n
		ni *= 5;
		ei++;
	}
	printf("%d\n", ei);

	return 0;
}


# 字符串轉數字,數字轉字符串。string 和 int 之間的轉化,當返回值不是基礎數據類型的時候,用自定義數據類型封裝

#include<stdio.h>
#include<string.h>
#include<string>
#include<iostream>
using namespace std;

struct Node{
	char cs[20];
};

// 當想返回的值不是基礎數據類型的時候,用結構體封裝
Node num2str(int n) {
	Node node;
	sprintf(node.cs, "%d", n);
	return node;
}

int str2num(char s[]) {
	int n = atoi(s);
	return n;
}

int main() {
	int  n = 777;
	printf("str = %s\n", num2str(n).cs);

	char cs[10];
	scanf("%s", cs);
	printf("num = %d\n", str2num(cs));

	// char []可以直接當string使用,string當char[]使用只能str.at(i)
	char cs2[] = "RunningZ";
	string str = cs2;
	cout << cs2 << endl;
	cout << str << endl;
	return 0;
}


#


# 自己實現的快排,遞歸形式

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
int a[2222222];

void qSort(int a[], int l, int r) {
	if (l >= r) return;
	int pl = l;
	int pr = r;
	int tmp = a[pl];
	while (pl < pr) { // 是 <, 而不是<=
		while (pl < pr && a[pr] >= tmp) pr--;
		if (pl >= pr) break; // 注意
		a[pl++] = a[pr];
		while (pl < pr && a[pl] <= tmp) pl++;
		if (pl >= pr) break;
		a[pr--] = a[pl];
	}
	a[pl] = tmp;
	qSort(a, l, pl - 1);
	qSort(a, pl + 1, r);
}

int main() {
	int i, n;
	n = 2222222;
	for (i = 0; i < n; i++) {
		a[i] = rand() % n;		
	}
	
	clock_t t1 = clock();
	//sort(a, a + n);
	qSort(a, 0, n - 1);
	clock_t t2 = clock();

	printf("time = %d\n", t2 - t1);
	return 0;
}

#

#  第K大數,快排的思想用來求第K大數,或者用來求中位數,時間複雜度爲O(n), 因爲F(n) = F(n / 2) + O(n分 + 1合併),故F(n) = O(n)

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
using namespace std;
int a[5000001];

int getMedian(int a[], int l, int r, int k) {
	// printf("l = %d, r = %d, k = %d\n", l, r, k);
	if (l == r && k == 0) return a[l];
	int pl = l;
	int pr = r;
	int tmp = a[l];
	while (pl < pr) {
		while (pl < pr && a[pr] > tmp) pr--;
		if (pl >= pr) break;
		a[pl++] = a[pr];
		while (pl < pr && a[pl] < tmp) pl++;
		if (pl >= pr) break;
		a[pr--] = a[pl];
	}
	a[pl] = tmp;

	if(pl - l == k) return tmp;
	if(pl - l >  k) {
		return getMedian(a, l, pl - 1, k);
	} else {
		return getMedian(a, pl + 1, r, k - (pl - l + 1));
	}
}

int main() {
	int i, n;
	n = 5000000;
	for (i = 0; i < n; i++) {
		a[i] = rand() % n;
		//printf("%d ", a[i]);
	}
	//printf("\n");
	clock_t t1 = clock();
	int median = getMedian(a, 0, n - 1, n / 2);
	printf("median = %d\n", median);
	clock_t t2 = clock();
	printf("time1 = %d\n", t2 - t1);
	
	t1 = clock();
	sort(a, a + n);
	printf("sort mid = %d\n", a[n>>1]);
	t2 = clock();
	printf("time2 = %d\n", t2 - t1);
}

#

# 排序

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;

struct Node {
	int x;
	int y;
};
int a[101];
Node node[101];
 
bool cmp1(const int x1, const int x2) {   // 遞增
	return x1 < x2;
}
bool cmp2(const Node n1, const Node n2) { // 遞減
	if (n1.x != n2.x) return n1.x > n2.x;
	return n1.y > n2.y;
}

int main() {
	int i, n;
	n = 10;
	for (i = 0; i < n; i++) {
		a[i] = rand() % 10;	  // 基本數據類型
		node[i].x = rand() % 10;  // 自定義數據類型
		node[i].y = rand() % 10;
	}

	sort(a, a + n, cmp1);	    // 數組頭,數組頭 + 個數,比較函數
	sort(node, node + n, cmp2); // 加法已經重載

	for (i = 0; i < n; i++) {
		printf("%d ", a[i]);
	} printf("\n");
	for (i = 0; i < n; i++) {
		printf("%d,%d ", node[i].x, node[i].y);
	} printf("\n");
	return 0;
}

#

# 數學相關,最大公約數,最小公倍數

#include<stdio.h>

int gcd(int n1, int n2) {
	int nMax = n1 > n2 ? n1 : n2;
	int nMin = n1 < n2 ? n1 : n2;
	if (nMax % nMin == 0) return nMin;
	
	return gcd(nMax % nMin, nMin);
}

int main() {
	int n1, n2;
	n1 = 12;
	n2 = 16;
	
	// 最大公約數
	int n12 = gcd(n1, n2);
	printf("%d\n", n12);

	// 最小公倍數
	int nn = n1 / gcd(n1, n2) * n2;
	printf("%d\n", nn);
	return 0;
}

#

# 素數篩選法,一般結合二分搜索

#include<stdio.h>
#include<math.h>

int a[1000001];
int prime[1000001];
int pi = 0;

void getPrime() {
	int i, j, n;
	n = 100;

	a[0] = 1; a[1] = 1;
	for (i = 3; i <=n; i++) {
		a[i] = i % 2 == 0 ? 1 : 0;
	}
	int sqrtN = sqrt(n);
	for (i = 3; i < sqrtN; i++) {
		if (a[i] != 0) continue;
		for (j = i * i; j <= n; j += i) {
			a[j]++;
		}
	}

	int count = 0;
	for (i = 0; i <= n; i++) {
		if (a[i] == 0) {
			count++;
			prime[pi++] = i;
			// printf("%d ", i);
		}
	}
	printf("count = %d\n", count);
}

int main() {
	getPrime();
	return 0;
}

#

# 全排列,DFS,用數組模擬棧

#include<stdio.h>

int used[20];
int stack[20];
int top = 0;

void permutation(int n, int deep) {
	int i;
	if (deep == n) {
		for (i = 0; i < top; i++) {
			printf("%d ", stack[i]);
		}
		printf("\n");
		return;
	}

	for (i = 1; i <= n ;i++) {
		if (used[i] == 1) continue;
		used[i] = 1;
		stack[top++] = i;
		permutation(n, deep + 1);
		stack[top--] = 0;
		used[i] = 0;
	}
}

void init(int n) {
	int i;
	for (i = 1; i <= n; i++) {
		used[i] = 0;
	}
	top = 0;
}

int main() {
	// freopen("out.txt",  "w", stdout);
	// n = 7時,輸出文件大小(7 * 2 + 2) * 7! = 80640 Byte, 數字在文件裏存成0~9的字符,每一位佔1個字節,回車佔兩個字節
	int i, n;
	n = 7;
	init(n);
	permutation(n, 0);
	return 0;
}

// 2016-5-9 12:43:37

#


<-------持續更新------->

<-------持續更新------->

<-------持續更新------->

<-------持續更新------->

<-------持續更新------->

<-------持續更新------->

<-------持續更新------->


@RunningZ

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章