Berechnungszeit, Ableitung der Zeitkomplexität und klassische Algorithmusanalyse von Divide and Conquer

Teilen und Erobern ist eine Idee zur Lösung komplexer Probleme. Sie kann ein Problem in mehrere kleine Probleme aufteilen und durch Zusammenführen dieser Probleme die Lösung des ursprünglichen Problems erhalten. Dieser Artikel analysiert die Komplexität der Divide-and-Conquer-Methode und analysiert die zeitliche Komplexität mehrerer spezifischer Algorithmen mithilfe dieser Methode.

1 Komplexitätsanalyse von Divide and Conquer

„Teile und herrsche“ kann die Größe n habenDas Problem von n ist in kkk Skalennm \frac {n}{m}Mnzu lösende Teilprobleme. Stellen Sie den Zerlegungsschwellenwert n 0 = 1 n_0=1 einN0=1 , und es dauert 1 Zeiteinheit, ein Problem der Größe 1 mit dem Algorithmus zur Lösung des kleinsten Teilproblems zu lösen. Zerlegen wir das ursprüngliche Problem inkkk Teilprobleme undkkDie Lösung von k Teilproblemen wird mitf ( n ) f(n)f ( n ) Zeiteinheiten. mitT ( n ) T(n)T ( n ) bedeutet, dass die Lösungsskala der Divide-and-Conquer-MethodennDie für das n- Problem erforderliche Berechnungszeit beträgt:
T ( n ) = { O ( 1 ) n = 1 k T ( nm ) + f ( n ) n > 1 T(n)=\begin{cases} O( 1) &n=1\\ kT(\frac{n}{m})+f(n)&n>1\\ \end{cases}T ( n )={ O ( 1 )k T (Mn)+f ( n )N=1N>1
T ( n ) = nlogmk + ∑ j = 0 logm ( n ) − 1 kjf ( nmj ) (1.1) T(n)=n^{log_m k}+\sum_{j=0}^{log_m(n) -1}k^jf(\frac{n}{m^j})\tag{1.1}T ( n )=Nl o gmk+j = 0l o gm( n ) 1kj f(MJn)( 1.1 )
„Einführung in Algorithmen“ verwendet einen rekursiven Baum bei der Ableitung der Formel (1.1). Hier versuchen wir, eine andere Methode zum Ableiten zu verwenden:
wennn > 1 n>1N>1时, T ( n ) = k T ( nm ) + f ( n ) , T(n)=kT(\frac{n}{m})+f(n),T ( n )=k T (Mn)+f ( n ) ,
sein = mtn=m^tN=Mt , 令G ( t ) = T ( mt ) = T ( n ) G(t)=T(m^t)=T(n)G ( t )=T ( mt )=T ( n ) , dann
T ( mt ) = k T ( mt − 1 ) + f ( mt ) G ( t ) = k G ( t − 1 ) + f ( mt ) = k ( k G ( t − 2 ) + f ( mt − 1 ) ) + f ( mt ) = k 2 G ( t − 2 ) + kf ( mt − 1 ) + f ( mt ) = ⋯ = kt G ( 0 ) + kt − 1 f ( m ) + kt − 2 f ( m 2 ) + ⋯ + kf ( mt − 1 ) + f ( mt ) = kt G ( 0 ) + ∑ j = 0 t − 1 kjf ( mt − j ) = klogmn + ∑ j = 0 logm ( n ) − 1 kjf ( nmj ) = nlogmk + ∑ j = 0 logm ( n ) − 1 kjf ( nmj ) \begin{split} T(m^t)&=kT(m^{t-1})+f(m^t )\\ G(t)&=kG(t-1)+f(m^t)\\ &=k(kG(t-2)+f(m^{t-1}))+f(m ^t)\\ &=k^2G(t-2)+kf(m^{t-1})+f(m^t)\\ &=\cdots\\ &=k^tG(0)+ k^{t-1}f(m)+k^{t-2}f(m^2)+\cdots+kf(m^{t-1})+f(m^t)\\ &= k^tG(0)+\sum_{j=0}^{t-1}k^jf(m^{tj})\\ &=k^{log_mn}+\sum_{j=0}^{log_m (n)-1}k^jf(\frac{n}{m^j})\\ &=n^{log_mk}+\sum_{j=0}^{log_m(n)-1}k^jf (\frac{n}{m^j})\\ \end{split}T ( mt )G ( t )=k T ( mt 1 )+f ( mt )=k G ( t1 )+f ( mt )=k ( k G ( t2 )+f ( mt 1 ))+f ( mt )=k2 G(t2 )+k f ( mt 1 )+f ( mt )==kt G(0)+kt 1 f(m)+kt 2 f(m2 )++k f ( mt 1 )+f ( mt )=kt G(0)+j = 0t 1kj f(mt j )=kl o gmN+j = 0l o gm( n ) 1kj f(MJn)=Nl o gmk+j = 0l o gm( n ) 1kj f(MJn)
Daher erhält man Formel (1.1): T ( n ) = nlogmk + ∑ j = 0 logm ( n ) − 1 kjf ( nmj ) T(n)=n^{log_mk}+\sum_{j=0}^{ log_m( n)-1}k^jf(\frac{n}{m^j})T ( n )=Nl o gmk+j = 0l o gm( n ) 1kj f(MJn)
Bei der Berechnung der Zeitkomplexität können Sien , m , kn,m,kn ,m ,K wird in die zu lösende Formel eingesetzt.

2 Klassische Algorithmenanalyse

2.1 Binäre Suche

Die binäre Suche erfolgt in einer geordneten Sequenz a [ 0 : n ] a[0:n]ein [ 0:n ] , um ein bestimmtes ElementxxDie Methode von x gibt die Position des Elements in der Sequenz zurück, wenn es gefunden wird, und gibt einen Suchfehler zurück, wenn das Element nicht in der Sequenz ist. Nehmen wir als Beispiel die aufsteigende Reihenfolge: Bei der Suche ist das gefundene Element jedes Malxxx und das mittlere Element der SequenzMitte Mittemid d zum Vergleich, wennx == midx==midX==mid d , die Position zurückgeben; wennx < mid x<midX<mid mid , was darauf hinweist, dass sich das gesuchte Element möglicherweise inmid midVor mid , kurz vora [ 0 : mid ] a[0:mid]ein [ 0:mid d ] auf die gleiche Weise weitersuchen; wennx > mid x>midX>mid mid , was darauf hinweist, dass sich das gesuchte Element möglicherweise inmid midNach mid , kurz nacha [ mid : n ] a[mid:n]a [ mi d:n ] , um die Suche auf die gleiche Weise fortzusetzen. Der Code (C-Sprache) lautet wie folgt:

int binary_search(int a[], int num, int low, int high)
//a:要查找的序列,num:要查找的数,low:查找序列的第一个元素,high:查找序列的最后一个元素
{
    
    
	int mid = 0;
	while (low <= high) 
	{
    
    
		mid = (low + high) / 2;
		if (num == a[mid]) return mid;
		else if (num < a[mid]) high = mid - 1;
		else low = mid + 1;
	}
	return -1;
}

Das binäre Suchproblem wird 1 der Größe nn seinDas Problem von n wird in 1 Größe n 2 \frac{n}{2}unterteilt2nDas Unterproblem des Problems, die Kosten für die Teilung des Problems, ergeben sich aus dem Vergleich von Zahlen, und am Ende ist keine Zusammenführung erforderlich, sodass nur eine konstante Zeitreihenfolge erforderlich ist, um ein Problem zu zerlegen und zu einem zusammenzuführen Problem, das heißt f ( n ) = cf(n)= cf ( n )=c , aus Formel (1.1) können wir erkennen, dass die für die binäre Suche erforderliche Zeit
T ( n ) = nlog 2 1 + ∑ j = 0 log 2 ( n ) − 1 c = 1 + clog 2 n \begin{split } T(n) &=n^{log_21}+\sum_{j=0}^{log_2(n)-1}c\\ &=1+clog_2n \end{split}T ( n )=Nl o g21+j = 0l o g2( n ) 1C=1+c l o g2n
Dann ist die Zeitkomplexität der binären Suche O ( log 2 n ) O(log_2n)O ( l o g2n ) .

2.2 Zwei-Wege-Zusammenführungssortierung

Bei der bidirektionalen Zusammenführungssortierung wird eine ungeordnete Sequenz a [low, high] a[low, high] erstellt.ein [ niedrig , _ _high g h ] wird in zwei Sequenzen gleicher Größe aufgeteilta [low, mid] a[low,mid]ein [ niedrig , _ _mi d ] ,a [ mid + 1 , high ] a[mid+1,high]a [ mi d+1 ,hi g h ] und sortieren Sie dann die beiden Sequenzen separat. Nachdem die Sortierung abgeschlossen ist, werden die beiden Sequenzen separat sortiert, und die Sortierung kann durch Zusammenführen der beiden Sequenzen abgeschlossen werden. Der C-Sprachcode lautet wie folgt:

void merge(int a[], int tmp[], int low, int mid, int high)
//合并算法,a[low,mid]有序,a[mid+1,high]有序,merge函数使得a[low,high]有序
{
    
    
	int i, j, k;
	for (i = low; i <= high; i++) tmp[i] = a[i];
	//将a[low,high]复制到tmp[low,high]中
	i = low, j = mid+1, k = low;
	//i,j用来指示数组tmp中的位置,k用来指示数组a中的位置
	while (i <= mid && j <= high)
	{
    
    
		if (tmp[i] <= tmp[j])
		//从tmp的两个有序段中挑出最小的元素放入a的下一个位置
		{
    
    
			a[k] = tmp[i];
			i++;
		}
		else
		{
    
    
			a[k] = tmp[j];
			j++;
		}
		k++;
	}
	while (i <= mid) //tmp[mid+1,high]已经在a中,将tmp[low,mid]中的剩余元素填入a
	{
    
    
		a[k] = tmp[i];
		i++, k++;
	}
	while (j <= high) //tmp[low,mid]已经在a中,将tmp[mid+1,high]中的剩余元素填入a
	{
    
    
		a[k] = tmp[j];
		j++, k++;
	}
}


void merge_sort(int a[], int tmp[], int low, int high)
//归并排序算法,a:要排序的数组,tmp:相同长度的辅助数组,low:排序序列的第一个元素,high:排序序列的最后一个元素
{
    
    
	int mid = 0, i;
	if (low < high)
	{
    
    
		mid = (low + high) / 2;
		merge_sort(a, tmp, low, mid);
		merge_sort(a, tmp, mid + 1, high);
		//将排序问题分成两个规模减半的子问题
		merge(a, tmp, low, mid, high);
		//将子问题的结果合并
	}
}

Der Zwei-Wege-Merge-Sortieralgorithmus hat eine Größe von nnDas Problem von n ist in 2 Skalen n 2 \frac{n}{2}unterteilt2nTeilproblem. Das Aufteilungsproblem wird durch Funktionsaufrufe implementiert, und das Zusammenführungsproblem verbringt hauptsächlich Zeit im Array aaa und das Arraytmp tmpt m p überträgt Elemente aufeinander, alsof ( n ) = nf(n)=nf ( n )=n , aus Formel (1.1) kann man erkennen, dass die für die bidirektionale Zusammenführungssortierung erforderliche Zeit ist:
T ( n ) = nlog 2 2 + ∑ j = 0 log 2 ( n ) − 1 2 jn 2 j = n + nlog 2 n \begin{ split} T(n)&=n^{log_22}+\sum_{j=0}^{log_2(n)-1}2^j\frac{n}{2^j} \\ &=n+nlog_2n \end{split}T ( n )=Nl o g22+j = 0l o g2( n ) 12J2Jn=N+n l o g2n
Dann beträgt die zeitliche Komplexität der bidirektionalen Zusammenführungssortierung O (nlog 2 n) O(nlog_2n)O ( n l o g2n ) .

Ich denke du magst

Origin blog.csdn.net/diqiudq/article/details/128589092
Empfohlen
Rangfolge