概要
アルゴリズムを設計する方法
2.3設計アルゴリズム
代わりに、多くのアルゴリズム設計、個々の要素の後に挿入ソート増分方法、ソートされたサブアレイA [1..j-1]サブアレイA [1..j]を生成し、そこです。分割統治下に考えるもう一つの方法は、挿入ソートの時間を実行している最悪の場合、分割統治がはるかに少ないそれよりも、利点の一つは、実行中の時間を決定するために非常に簡単であることが多いです。
2.3.1分割統治
構造体の多くの有用なアルゴリズムは再帰的です。イデオロギー分割統治:いくつかの小さな規模に元の問題が、元の問題の類似サブ問題、これらのサブ問題を解決する再帰的な、元の問題の解決策を確立するこれらのサブ問題のその後脱合併。
3つの段階で各再帰パーティション:
サブ問題のオリジナルの問題に対する解決策を合わせたサブ問題のソリューションを解決するために、サブ問題に元の問題を分解する。
:パーティションのマージソート方法従う
N / 2要素を有する二つのサブシーケンスに分類されるn個の要素の分解。再帰的にソート二つのサブシーケンスを注文マージを使用して、シーケンスは、2つの整理生成ソートマージ。
コアコード
package notes.javase.algorithm.sort;
public class MergeSort {
public void Merge(int[] array, int low, int mid, int high) {
int i = low; // i是第一段序列的下标
int j = mid + 1; // j是第二段序列的下标
int k = 0; // k是临时存放合并序列的下标
int[] array2 = new int[high - low + 1]; // array2是临时合并序列
// 扫描第一段和第二段序列,直到有一个扫描结束
while (i <= mid && j <= high) {
// 判断第一段和第二段取出的数哪个更小,将其存入合并序列,并继续向下扫描
if (array[i] <= array[j]) {
array2[k] = array[i];
i++;
k++;
} else {
array2[k] = array[j];
j++;
k++;
}
}
// 若第一段序列还没扫描完,将其全部复制到合并序列
while (i <= mid) {
array2[k] = array[i];
i++;
k++;
}
// 若第二段序列还没扫描完,将其全部复制到合并序列
while (j <= high) {
array2[k] = array[j];
j++;
k++;
}
// 将合并序列复制到原始序列中
for (k = 0, i = low; i <= high; i++, k++) {
array[i] = array2[k];
}
}
public void MergePass(int[] array, int gap, int length) {
int i = 0;
// 归并gap长度的两个相邻子表
for (i = 0; i + 2 * gap - 1 < length; i = i + 2 * gap) {
Merge(array, i, i + gap - 1, i + 2 * gap - 1);
}
// 余下两个子表,后者长度小于gap
if (i + gap - 1 < length) {
Merge(array, i, i + gap - 1, length - 1);
}
}
public int[] sort(int[] list) {
for (int gap = 1; gap < list.length; gap = 2 * gap) {
MergePass(list, gap, list.length);
System.out.print("gap = " + gap + ":t");
this.printAll(list);
}
return list;
}
// 打印完整序列
public void printAll(int[] list) {
for (int value : list) {
System.out.print(value + "t");
}
System.out.println();
}
public static void main(String[] args) {
int[] array = {
9, 1, 5, 3, 4, 2, 6, 8, 7
};
MergeSort merge = new MergeSort();
System.out.print("排序前:tt");
merge.printAll(array);
merge.sort(array);
System.out.print("排序后:tt");
merge.printAll(array);
}
}
大きな箱 のアルゴリズム入門ノート3「タイトル=」効率のマージソート:「>効率のマージソート:
時間計算:マージソートバイナリツリーの形で、深さの二分木をトラバースするのに必要とされ、そして完全なバイナリツリーは、その時間複雑に従って導出することができる回数はO(ログN - *である2 N-)。
宇宙複雑:上記のアルゴリズムにより、アルゴリズムのプロセスは、マージされたシーケンスを保存するための大きさのn一時的な記憶を必要とします。
安定性アルゴリズム:それは安定したアルゴリズムであるように、マージソート等しい要素の順序では、変更されません。
マージソートを比較して、ヒープソート、クイックソートの
- スペースの複雑さを考慮した場合:優先ヒープソート、クイックソートに続いて、最後にマージソート。
- ヒープソートとクイックソート不安定であるため、安定性から考えるとは、マージソートを選択する必要があります。
- 平均的なケースからの発注の速さを考えると、あなたはクイックソートを選択する必要があります。
練習
1.バイナリ検索
再帰的なアルゴリズムが与えられた、明らかに時間を実行して、最悪の場合には(ログOで2 N-)を
/**
* 二分查找,找到该值在数组中的下标,否则为-1
*/
static int binarySerach(int[] array, int key) {
int left = 0;
int right = array.length - 1;
// 这里必须是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] == key) {
return mid;
}
else if (array[mid] < key) {
left = mid + 1;
}
else {
right = mid - 1;
}
}
return -1;
}
2.バイナリ挿入ソートを向上検索すると、合計実行時間を改善することができます
//二分查找
public static int binarySearch(int array[],int low,int high,int temp)
{
int mid=0;
while(low<=high)
{
mid=(low+high)/2;
if(array[mid]<temp&&temp<=array[mid+1])
return (mid+1);
else if(array[mid]<temp)
low = mid + 1;
else
high = mid -1;
}
return high;
}
//二分排序
public static void binarySort(int array[],int size)
{
int i,j,k,temp;
for(i=1;i<size;i++)
{
temp=array[i];
if(array[i]<array[0])
k=0;
else
k = binarySearch(array,0,i,temp);
for(j=i;j>k;j--)
{
array[j]=array[j-1];
}
array[k]=temp;
System.out.println(Arrays.toString(array));
}
}
最悪の場合には、二分探索時間の複雑さはnlgnであるが、アレイの時間複雑性は依然としてN-挿入中に移動している2。これは、全体の実行時間はO(nlgn)ですが、データ構造は、リストをソートするために使用した場合、改善することができる改善されません。
3 O(nlgn)アルゴリズム、所与のセットのS nは整数xおよび他の整数の実行時間を記述し、アルゴリズムが正確に要素xを従事している2つのSがあるかどうかを判定することができます
入力:配列A、整数X
擬似コード:
A=Sort(A)//对数组A排序
n=length[A]//n为数组A的长度
for i=0 to n-1 do
if A[i]>=0 and Binary_search(A,x-A[i],1,n) then //用二分查找看x-A[i]是否在数组A中
return true
end if
end for
return false