Data Structure第六次作業講解


Data Structure第六次作業講解

寫給讀者的話(務必閱讀)

期中以來,有不少同學向我反應代碼寫的慢、正確率不高等問題。由於OS已經爆炸閑的沒事干 因此我決定將自己原來寫的代碼重構重構,並整理成博客附上整個思路的講解。首先,我必須申明,博客所寫的東西,是供想提升自己代碼水平,理清寫碼思路的同學用的。我希望同學們能夠明白:作為一個考試分數占 80% 的學科,抄襲他人代碼完成作業不是白賺了那 20% 的分數,而是失去了一次良好的練兵的機會(從本次開始,文章中給出的代碼均已提交評測,抄襲需謹慎)。其次,個人所寫代碼只是提供一個寫碼、思考問題的思路,並不代表題目的唯一解法,更不代表最優解法沒有提交到課程網站上測試,只在本地通過測試數據,甚至可能有bug噢。我希望我的代碼能夠起到拋磚引玉的作用,能夠讓同學對課上內容有更深刻的理解,寫代碼時能夠有更多更好的想法。最后,我希望同學們在完成作業的同時,能夠對自己的代碼進行復雜度的分析。數據結構的使用,往往離不開對性能的約束,因此,掌握復雜度的分析也是這門課程重要的一環。

關於代碼風格

本文中所有的代碼風格皆采取 OO 的標准,同時作者也希望同學們能夠以這種標准約束自己,這樣也會方便助教 debug。簡單來說,大致約束如下:

1、符號后帶空格。

2、大括號不換行。

3、if、while、for 等括號兩端應該帶空格,並且一定要用大括號括起來。

4、一行不要寫過多字符(不超過60),較長的判斷可以換行處理。

5、縮進為 4 個空格,不同層次間要有合適的縮進。

6、一行只聲明一個變量,只執行一個語句。

關於使用到的工具

采取了dhy大佬的意見,決定新添加這個欄目,對本次代碼中使用到的基礎的一些數據結構或是函數進行一些簡單的講解,便於大家的使用和理解。

1、快速讀入

inline int read() { //快速讀入,可以放在自己的缺省源里面 
	int x = 0; //數字位 
	int f = 1; //符號位 
	char ch = getchar(); //讀入第一個字符 
	while (!isdigit(ch)) { //不是數字 
		if (ch == '-') { //特判負號 
			f = -1;
		}
		ch = getchar();
	}
	while (isdigit(ch)) { //讀入連續數字 
		x = (x << 3) + (x << 1) + ch - '0'; // x * 10 == (x << 3) + (x << 1) 
		ch = getchar();
	}
	return x * f;
}

快速讀入是比較好用的一種讀入的寫法,我這里的實現是通過循環讀入直到得到下一個數字,在具體的題目中也可以根據自己的需要對循環的條件和結束條件做更改來讀入字符串等。(由於只涉及到簡單循環,這里不作更深入的講解)。切忌不經思考和理解就使用,容易出現讀入死循環等問題。

2、鏈式前向星

在解決需要建邊(如:樹、圖)相關的問題時,比較方便的一種數據結構。在第一道題中用到了類似的結構,因此我們在這里做個講解。

typedef struct edge {
	int to; //指向這條邊到達的對象
	int nxt; //指向當前表頭的下一條邊,為 0 則代表沒有
} Edge;
Edge e[maxn];
int h[maxn];
int cnt;

void adde(int x, int y) { //建一條 x 向 y 的邊
	e[++cnt] = (Edge) {y, h[x]}; //產生新的指向 y 的表頭,並將 nxt 指向之前的表頭
	h[x] = cnt; //更新表頭
}

void forEach(int x) {
	int i;
	for (i = h[x]; i; i = e[i].nxt) { //遍歷時從表頭開始依次訪問每個邊,取出其指向的點
		int y = e[i].to;
		forEach(y);
	}
}

如此圖所示,我們新加入編號為 3 的邊

初始狀態 e[1] = {2, 0} (前面為to,后面為nxt)

​ e[2] = {3, 1}

​ h[1] = 2

這時我們新建 e[3] = {4, h[1]} 即 {4,2}

再令 h[1] = 3

那么遍歷的時候我們可以通過 h[1] 找到 e[3],再通過 e[3].nxt 找到 e[2], 再通過 e[2].nxt 找到 e[1],就獲得了完整的邊的信息。

第一題:單詞查找(查找-基本題)

題目描述

【問題描述】

從標准輸入中讀入一個英文單詞及查找方式,在一個給定的英文常用單詞字典文件dictionary3000.txt中查找該單詞,返回查找結果(查找到返回1,否則返回0)和查找過程中單詞的比較次數。查找前,先將所有字典中單詞讀入至一個單詞表(數組)中,然后按要求進行查找。字典中單詞總數不超過3500,單詞中的字符都是英文小寫字母,並已按字典序排好序(可從課件下載區下載該字典文件)。字典中的單詞和待查找單詞的字符個數不超過20。

查找方式說明:查找方式以1~4數字表示,每個數字含義如下:

1:在單詞表中以順序查找方式查找,因為單詞表已排好序,遇到相同的或第一個比待查找的單詞大的單詞,就要終止查找;

2:在單詞表中以折半查找方式查找;

3:在單詞表中通過索引表來獲取單詞查找范圍,並在該查找范圍中以折半方式查找。索引表構建方式為:以26個英文字母為頭字母的單詞在字典中的起始位置和單詞個數來構建索引表,如:

字母 起始位置 單詞個數
a 0 248
b 248 167

該索引表表明以字母a開頭的單詞在單詞表中的開始下標位置為0,單詞個數為248。

4:按下面給定的hash函數為字典中單詞構造一個hash表,hash沖突時按字典序依次存放單詞。hash查找遇到沖突時,采用鏈地址法處理,在沖突鏈表中找到或未找到(遇到第一個比待查找的單詞大的單詞或鏈表結束)便結束查找。

/* compute hash value for string */

#define NHASH 3001

#define MULT 37

unsigned int hash(char *str)

{

​ unsigned int h=0;

​ char *p;

​ for(p=str; *p!='\0'; p++)

​ h = MULT*h + *p;

​ return h % NHASH;

}

提示:hash表可以構建成指針數組,hash沖突的單詞形成一有序鏈表。

【輸入形式】

單詞字典文件dictionary3000.txt存放在當前目錄下,待查找單詞和查找方式從標准輸入讀取。待查找單詞只包含英文小寫字母,與表示查找方式的整數之間以一個空格分隔。

【輸出形式】

將查找結果和單詞比較次數輸出到標准輸出上,兩整數之間以一個空格分隔。
【樣例輸入與輸出】
單詞字典文件dictionary3000.txt與課件下載中提供的相同,下面兩列中,左側為待查找單詞與查找方式,右側為對應的輸出結果:

wins 1 0 3314

wins 2 0 12

wins 3 0 7

wins 4 0 2

yes 1 1 3357

yes 2 1 10

yes 3 1 4

yes 4 1 1
【樣例說明】

wins在單詞字典中不存在,4種查找方式都輸出結果0,順序查找、折半查找、索引查找和hash查找的單詞比較次數分別為:3314、12、7和2次(wins的hash位置與字典中physics和suggest相同)。

yes在單詞字典中存在,4種查找方式都輸出結果1,順序查找、折半查找、索引查找和hash查找的單詞比較次數分別為:3357、10、4和1。

題目大意

按照題目所給的要求用多種查找方式和hash表來對單詞進行查找並且輸出查找的次數。

題目思路

我們按照題目的要求來模擬每種查找方式就可以了。

第一種:順序查找我們直接用數組存儲所有的串枚舉即可

第二種:二分查找,每次找中間的比對更改上下界即可(讀入保證字符串順序)

第三種:限定區間的二分查找,我們在字母變化的時候預處理區間的范圍就可以了

第四種:hash,用鏈表串起來查找就行

代碼實現

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

#define maxn 3505
#define NHASH 3001
#define MULT 37

typedef struct line {
	char* s;
	int nxt;
} Line;

int h[NHASH];
Line l[maxn];
char s[maxn][25];
int B[255], E[255], cnt;

unsigned int hash(char *str){ //直接用題目給的代碼
       unsigned int h=0;
       char *p;
       for(p=str; *p!='\0'; p++){
           h = MULT*h + *p;
       }
       return h % NHASH;
}

void Push(int nw, char *s) {
	++cnt;
	l[cnt].s = s;
	if (!h[nw]) { //第一個讀入的,特判
		h[nw] = cnt;
		return;
	}
	if (strcmp(l[h[nw]].s, s) > 0) { //當前串直接比鏈表首還大,特判更改 
		l[cnt].nxt = h[nw];
		h[nw] = cnt;
		return;
	}
	int lst, i;
	for (i = h[nw]; i && strcmp(l[i].s, s) < 0; i = l[i].nxt) {//找到第一個小於當前串的位置 
		lst = i; //保存上一個比當前串大的位置。 
	}
	l[cnt].nxt = l[lst].nxt; //接入當前串
	l[lst].nxt = cnt;
}

int Init() { //初始化讀入,並作必要的處理。 
	FILE* IN;
	IN = fopen("dictionary3000.txt", "r");
	int t = 0;
	while(fscanf(IN, "%s", s[t]) != EOF) {
		if (s[t][0] != s[t - 1][0]) { //說明首字母出現了變化,我們更改首字母的開始結束 
			int i;
			for (i = s[t - 1][0] + 1; i < s[t][0]; ++i) { //中間的字母沒有出現過,特殊處理 
				B[i] = E[i] = t;
			}
			E[s[t - 1][0]] = B[s[t][0]] = t; //更新上一個字母結尾和新字母開始 
		}
		int nw = hash(s[t]); //調用給出函數計算hash值
		Push(nw, s[t]); //放入鏈表里面進行管理 
		++t;
	}
	--t; //最后讀入了 EOF
	int i;
	for (i = 'z'; i > s[t][0]; --i) {//別忘了剩余沒讀入的字母 
		B[i] = E[i] = t; 
	}
	return t; //返回讀入總數	
}

void Print(int ans, int qcnt) {
	printf("%d %d\n", ans, qcnt);
}

void query_normal(char* q, int total) { //最簡單的順序查找 
	int ans = 0;
	int qcnt = 0;
	int i;
	for (i = 0; i <= total; ++i) {
		++qcnt;
		if (strcmp(q, s[i]) == 0) { //找到
			ans = 1;
			break;
		} 
		if (strcmp(q, s[i]) < 0) { //不可能找到結束
			break;
		}
	}
	Print(ans, qcnt);
}

void query_div(char* q, int total, int L, int R) {
	int qcnt = 0;
	int ans = 0;
	while (L <= R) { // 標准二分 
		int mid = (L + R) >> 1;
		++qcnt;
		if (strcmp(s[mid], q) == 0) { //找到
			ans = 1;
			break;
		}
		if (strcmp(q, s[mid]) < 0) { //更改上下界
			R = mid - 1;
		} else {
			L = mid + 1;
		}
	}
	Print(ans, qcnt);
}

void query_hash(char* q) {
	int nw = hash(q); //獲得hash值,遍歷鏈表
	int ans = 0;
	int qcnt = 0;
	int i;
	for (i = h[nw]; i; i = l[i].nxt) {
		++qcnt;
		int t = strcmp(l[i].s, q);
		if (t == 0) {
			ans = 1;
			break;
		}
		if (t > 0) {
			break;
		}
	}
	Print(ans, qcnt);
}

int main() {
	int total = Init();
	char q[25];
	int ty;
	scanf("%s%d", q, &ty);
	if (ty == 1) {
		query_normal(q, total);
	}
	if (ty == 2) {
		query_div(q, total, 0, total);
	}
	if (ty == 3) {
		query_div(q, total, B[q[0]], E[q[0]] - 1); //上下界為之前預處理的首字母對應的 B 和 E
	}
	if (ty == 4) {
		query_hash(q);
	}
	return 0;
} 

復雜度分析

第一種查詢方式復雜度 O(n * |S|)

第二種方式復雜度O(logn * |S|)

第三種方式復雜度O(logt * |S|) // t 代表 max(首字母相同的串的個數)

第四種方式可以根據模數算出平均沖突次數,這里就不作分析了。

第二題:排座位(簡)a

題目描述

【問題描述】

某班級要進行期末考試,准備考試時打亂座次,現已按照學號順序人工為學生隨機安排了座位號,但其中可能會出現漏排和重復安排座位的情況。編寫程序讀入人工安排的考試座位安排表T1,對安排情況進行檢查,並對漏排和重復安排座位的情況進行修正,修正后,若學生人數為N,則每位學生考試座位安排應在1~N之間,其中沒有缺號和重號。假設T1中學號信息不會出現重復,同一座位號最多有兩位同學的座位號相同,並且座位號不會連續漏排;初始考試座位安排表存放在當前目錄下的in.txt中,其中包括每位學生的學號、姓名和座位號,要求修正后的考試座位安排表輸出到當前目錄下的out.txt文件中。程序檢查座位號的規則如下:
1、首先對考試座位安排表T1按座位號從小到大的順序排序(原始考試安排可能有座位號相同情況,座位號相同時則按原始學號順序排序),得到按座位號排序的安排表T2;

2、對表T2從頭開始檢查漏排座位號情況:假設當前表中安排的最大座位號為M,取M和N的較小值Q;從1號開始檢查,若某個小於等於Q的座位序號沒有安排學生,則將表T2的最后學生的座位設置為該座位號;若存在多個漏排座位,則從表T2最后依次向前設置;

3、然后再檢查表T2中重排座位號情況:假設當前表中安排的最大座位號為m,將座位號重復的、學號較大的學生的座位號依次設置為m+1、m+2、m+3......;

\4. 將調整好的表T2按學號由小到大序排序后按輸出格式要求輸出至指定輸出文件中。

【輸入形式】

從標准輸入中讀入學生人數(不超過100的正整數)。

初始考試座位安排表存儲在當前目錄下的in.txt文件中,已按照學號由小到大的順序分行存儲每位學生座位信息,依次為學生學號(不超過8位的正整數)、姓名(由不超過20位的英文字母組成)和座位號(不超過100的正整數),各數據間以一個空格分隔。最后一個學生座位信息后有回車換行。

【輸出形式】

按照學號由小到大的順序將修正后的考試座位安排表輸出到當前目錄下的out.txt文件中,每行依次為學號、姓名和座位號,各數據之間以一個空格分隔。

題目大意

按照題目的意思去模擬一個排序過程即可。

題目思路

模擬排序過程,沒有什么特殊的思路,活用快排可以很簡單地解決這個問題。

需要注意的是,第二部分的 Q 是隨着處理的過程動態變化的,只取最開始的值會出問題。

比如下面這個例子:

a 1

b 2

c 2

d 3

e 4

f 4

g 5

h 7

初始的時候,我們不難發現,Q = min(N, M) = 7

然后枚舉1到7,在 6 的時候發現空位,把 h 座位改成 6

結果因為 7 的位置被空出來, 7 的時候發現空位,又把 h 座位改成 7,就違背了我們把前面座位排滿的意圖。

代碼實現

#include<stdio.h>
#include<string.h>
#define maxn 1005

typedef struct student{
	int num;
	int pos;
	char name[25];
} Student;

Student stu[maxn];

int n; 

int sort_pos(const void* a, const void *b) {//按照座位排序,座位相同時按學號 
	Student* s1 = (Student*) a;
	Student* s2 = (Student*) b;
	if (s1->pos == s2->pos) {
		return s1->num - s2->num;
	}
	return s1->pos - s2->pos;
}

int sort_num(const void* a, const void* b) {//按照學號排序 
	Student* s1 = (Student*) a;
	Student* s2 = (Student*) b;
	return s1->num - s2->num;
}

int max(int x, int y) { //三目運算符返回最大值 
	return x > y ? x : y;
} 

int min(int x, int y) { //三目運算符返回最小值 
	return x < y ? x : y;
}

int used[maxn]; // 每個座位是否被使用的標記 

int q[maxn]; //存儲座位重復的人的編號 
int qcnt;

int solve_empty() { //處理漏排座位 
	int Q = min(n, stu[n - 1].pos);
	int t = n - 1; //當前最末尾的人對應的編號
	int i;
	for (i = 0; i < n; ++i) { //標記已經使用過的座位 
		++used[stu[i].pos];
	} 
	for (i = 1; i <= Q; ++i) {
		if (!used[i]) {
			--used[stu[t].pos];
			stu[t--].pos = i;
			++used[i];
		}
		Q = min(Q, stu[t].pos); //記得動態更新 Q
	}
	int maxUsed = 0;
	for (i = 0; i < n; ++i) {
		used[stu[i].pos] = 0;
		maxUsed = max(maxUsed, stu[i].pos);
	}
	qcnt = 0;
	for (i = 0; i < n; ++i) {
		if (!used[stu[i].pos]) { //第一次使用這個座位
			used[stu[i].pos] = 1;
		} else { //和前面使用座位沖突
			q[qcnt++] = i;
		}
	} 
	return maxUsed;
}

int sort_dup(const void* a, const void* b) {
	int* n1 = (int*) a;
	int* n2 = (int*) b;
	return stu[*n1].pos - stu[*n2].pos;
}

void solve_dup(int maxUsed) { //處理重復座位 
	qsort(q, qcnt, sizeof(int), sort_dup);
	//之前我們處理之后,每個人的座位是亂序的,這里最好重新按座位大小排序 
	//其實不用排序 
	int i = 0;
	for (i = 0; i < qcnt; ++i) {
		stu[q[i]].pos = ++maxUsed;
	}
}

int main(){
	scanf("%d", &n);
	FILE *IN = fopen("in.txt", "r");
	FILE *OUT = fopen("out.txt", "w");
	int i;
	for (i = 0; i < n; ++i) {
		fscanf(IN, "%d%s%d", &stu[i].num, stu[i].name, &stu[i].pos); //讀入所有數據 
	}
	qsort(stu, n, sizeof(Student), sort_pos);  //按座位排
	int maxUsed = solve_empty(); //記錄當前最大座位編號
	solve_dup(maxUsed);
	qsort(stu, n, sizeof(Student), sort_num); //按學號排
	for(i = 0; i < n; ++i) {
		fprintf(OUT,"%d %s %d\n", stu[i].num, stu[i].name, stu[i].pos);
	}
	return 0;
}

復雜度分析

由於涉及到排序,復雜度是 O(nlogn * |S|) 的。

第三題:整數排序(排序-基本題)

題目描述

【問題描述】

從標准輸入中輸入一組互不相同的整數(個數不超過100)及排序方式,按照從小到大排序,輸出按某種算法排序的結果及元素的比較次數。

說明:排序方式為一個1~5的整數,分別表示:

1:選擇排序,比較次數是指選擇未排序部分的最小元素時的比較次數。

2:冒泡排序,比較次數是指相鄰元素的比較次數,若某趟排序中沒有進行數據交換,就認為排序結束。

3:堆排序,比較次數是指根元素調整過程中根元素與子樹根結點的比較次數,即下面算法中紅色語句的執行次數:

void adjust(int k[ ],int i,int n)

{

int j,temp;

temp=k[i];

j=2*i+1;

while(j<n){

​ if(j<n-1 && k[j]<k[j+1])

​ j++;

​ if(temp>=k[j])

​ break;

​ k[(j-1)/2]=k[j];

​ j=2*j+1;

}

k[(j-1)/2]=temp;

}

4:二路歸並排序,比較次數是指兩組有序數據合並成一組時的比較次數,即下面算法中紅色語句的執行次數(注意:調用 merge時,要使用上課講的遞歸算法):

void merge(int x[ ],int tmp[ ],int left,int leftend,int rightend)

{

int i=left, j=leftend+1, q=left;

while(i<=leftend && j<=rightend)

{

​ if(x[i]<=x[j])

​ tmp[q++]=x[i++];

​ else

​ tmp[q++]=x[j++];

}

while(i<=leftend)

​ tmp[q++]=x[i++];

while(j<=rightend)

​ tmp[q++]=x[j++];

for(i=left; i<=rightend; i++)

​ x[i]=tmp[i];

}

5:快速排序,比較次數是指分界元素與其它元素的比較次數,即下面算法中紅色語句的執行次數:

void quickSort(int k[ ],int left,int right)

{

int i, last;

if(left<right){

​ last=left;

​ for(i=left+1;i<=right;i++)

​ if(k[i]<k[left])

​ swap(&k[++last],&k[i]);

​ swap(&k[left],&k[last]);

​ quickSort(k,left,last-1);

​ quickSort(k,last+1,right);

}

}

【輸入形式】

首先在屏幕上輸入2個整數,分別表示待排序的整數個數及排序方式,然后在下一行依次輸入待排序的整數。各整數之間都以一個空格分隔。

【輸出形式】

先在一行上輸出排序結果,各整數間以一個空格分隔。然后在下一行上輸出排序過程中的元素比較次數。

題目大意

與第一題類似,用多種方式進行排序同時統計比較次數。

題目思路

沒什么特別的思路,模擬即可,注意在每次數字出現比較的時候給cnt + 1。

代碼實現

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#define maxn 105
#define INF 1e9

inline int read() { //快速讀入,可以放在自己的缺省源里面 
	int x = 0; //數字位 
	int f = 1; //符號位 
	char ch = getchar(); //讀入第一個字符 
	while (!isdigit(ch)) { //不是數字 
		if (ch == '-') { //特判負號 
			f = -1;
		}
		ch = getchar();
	}
	while (isdigit(ch)) { //讀入連續數字 
		x = (x << 3) + (x << 1) + ch - '0'; // x * 10 == (x << 3) + (x << 1) 
		ch = getchar();
	}
	return x * f;
}

int n;
int ty;
int a[maxn];
int used[maxn];

void selectionSort() { //選擇排序 
	int i, j;
	int cnt = 0;
	for (i = 1; i <= n; ++i) {
		int MIN = INF;
		int pos;
		for (j = 1; j <= n; ++j) {
			if (!used[j]) { //找還沒被選出的最小的 
				++cnt; //比較一次 
				if (a[j] < MIN) {
					MIN = a[j];
					pos = j;
				}
			}
		}
		--cnt; //選中第一個數並不需要比較,次數減一 
		used[pos] = 1;
		printf("%d ", MIN); //直接輸出找到的最小值 
	}
	puts("");
	printf("%d", cnt);
} 

void swap(int *a, int *b) { //交換兩個數 
	int c;
	c = *a;
	*a = *b;
	*b = c;
} 

void bubbleSort() { //冒泡排序 
	int i;
	int j;
	int cnt = 0;
	for (i = 1; i < n; ++i) {
		int tag = 0;
		for (j = 1; j <= n - i; ++j) {
			++cnt; //比較一次 
			if (a[j] > a[j + 1]) { //冒泡排序前后交換條件 
				swap(&a[j], &a[j + 1]);
				tag = 1;
			}
		}
		if (!tag) { //沒有產生交換 
			break;
		}
	}
	for (i = 1; i <= n; ++i) {
		printf("%d ", a[i]);
	}
	puts("");
	printf("%d", cnt);
}

//注意,標算給的是大根堆 

void adjust(int t, int* cnt) { //與自己的兩個兒子進行比較進行調整 
	while (1) {
		if ((t << 1) > n) {
			break;
		}
		++(*cnt);
		int p = t << 1;
		if ((t << 1 | 1) <= n && a[p] < a[t << 1 | 1]) { //比較找出左右兒子較大的那個 
			p = t << 1 | 1;
		}
		if (a[t] < a[p]) { //比較兒子和當前點 
			swap(&a[t], &a[p]);
		} else {
			break;
		}
		t = p;
	}
}

void heapSort() { //堆排序 
	int i;
	int cnt = 0;
	for (i = n >> 1; i >= 1; --i) { //自底向上調整堆 
		adjust(i, &cnt);
	}
	int lst = n; //記錄原本的個數 
	for (i = n; i >= 1; --i) {
		swap(&a[1], &a[n]); //把最大的換到最后 
		--n;
		adjust(1, &cnt);
	}
	for (i = 1; i <= lst; ++i) {
		printf("%d ", a[i]);
	}
	puts("");
	printf("%d ", cnt);
}

int b[maxn];
void merge(int l, int r, int* cnt) {
	if (l == r) { //相等返回 
		return;
	}
	int mid = (l + r) >> 1;
	merge(l, mid, cnt);
	merge(mid + 1, r, cnt); //先處理兩邊
	int l1 = l;
	int l2 = mid + 1;
	int nw = l;
	while (l1 <= mid && l2 <= r) { //兩端都還有值可用 
		++(*cnt);
		if (a[l1] <= a[l2]) {
			b[nw++] = a[l1++];
		} else {
			b[nw++] = a[l2++];
		}
	} 
	while (l1 <= mid) { //左邊未排完 
		b[nw++] = a[l1++]; 
	}
	while (l2 <= r) { //右邊未排完 
		b[nw++] = a[l2++];
	}
	int i;
	for (i = l; i <= r; ++i) { //將臨時的 b 復制給 a 
		a[i] = b[i];
	} 
}

void mergeSort() { //歸並排序 
	int cnt = 0, i;
	merge(1, n, &cnt);
	for (i = 1; i <= n; ++i) {
		printf("%d ", a[i]);
	}
	puts("");
	printf("%d", cnt);
}

void qSort(int l, int r, int* cnt) {
	if (l > r) {
		return;
	}
	int i;
	int lst;
	lst = l; //以 l 來比較大小 
	for (i = l + 1; i <= r; ++i) {
		++(*cnt);
		if (a[i] < a[l]) {
			swap(&a[++lst], &a[i]);
		}
	}
	swap(&a[l], &a[lst]);// 將 l 放在最后一個比它小的后面  
	qSort(l, lst - 1, cnt);
	qSort(lst + 1, r, cnt);
}

void quickSort() { //快速排序 
	int cnt = 0;
	int i;
	qSort(1, n, &cnt);
	for (i = 1; i <= n; ++i) {
		printf("%d ", a[i]);
	}
	puts("");
	printf("%d", cnt);
}

int main() {
	n = read();
	ty = read();
	int i;
	for (i = 1; i <= n; ++i) {
		a[i] = read();
	}
	if (ty == 1) {
		selectionSort(); 
	}
	if (ty == 2) {
		bubbleSort();
	}
	if (ty == 3) {
		heapSort();
	}
	if (ty == 4) {
		mergeSort();
	}
	if (ty == 5) {
		quickSort();
	}
	return 0;
}

復雜度分析

復雜度就是每種排序的復雜度。

搖起來

大巴黎,咚咚咚


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM