1. 程式人生 > >雙指標演算法以及各種應用

雙指標演算法以及各種應用

這裡雙指標指的是在同一個可迭代物件a中使用兩個迭代器(下面用i,j)。

反正就要能類似陣列這樣使用索引i, j來得到對應的值a[i], a[j],然後通過移動i跟j達到目的。下面以陣列為例

常見的使用方法有幾種:

1. i跟j在陣列的兩邊開始,用來把陣列分成兩部分

這個我們早遇到過了,我第一次遇見它被用來分成大於最左邊的數(基準數)跟小於最左邊的數兩部分。不過它結合了分治法導致你可能沒發現,它就是快速排序。當然快速選擇演算法中也是同樣。記得注意是括號裡是取小於等於,因為我們只把右邊小於(或大於)的數丟到另一邊。

//雙指標分組:將陣列分成>=temp以及<=temp的兩部分 
int quickSort(int a[], int left, int right)
{
	int i = left, j = right;
	int temp = a[left]; 
	while(i < j)
	{
		// 這個可以不需要=,但浪費時間,比起換來換去排序好,不如不動就排序好 
		while(a[j] >= temp && i < j)
			j--;
		// i必須有=,否則才第一個就不會動 
		while(a[i] <= temp && i < j)
			i++;
		
		if(i < j)
		{
            //交換兩個數的函式,可以自己編寫或者加入algorithm標頭檔案使用
			swap(a[i], a[j]);
			
		}
	}
	swap(a[left], a[i]);
	return i;
}

//分治法 
void quick(int a[], int left, int right)
{
	if(left >= right)
		return;
	int mid = quickSort(a, left, right);
	quick(a, left, mid-1);
	quick(a, mid + 1, right);
	
}

當然,它還可以用來分奇偶數。

void division(int a[], int n)
{  
    int i = 0, j = n - 1;  
        while(true)
        {  
            while(i < j && a[i] % 2 == 1) i++;  
            while(i < j && a[j] % 2 == 0) j--;  
            if(i < j)
            {  
                swap(a[i], a[j]);
            }  
        }  
 }  

2. 快慢指標:求不定長陣列(連結串列)的中間元素(1/3,1/4都一樣)

思路:使用兩個指標,快指標速度是慢指標的2倍(若1/3則3倍,1/4則4倍),當快指標到達終點時,慢指標到達所求的點

List middle(List)
{
    List qucik = a;
    List slow = a;
    
    while(quick != NULL && quick->next != NULL)
    {
        qucik = quick->next->next;
        slow = slow->next;
    }
    return slow;
}

 

3. 固定距離指標: 求距離n的點

比如,求連結串列倒數第n個節點

思路:使用兩個指標,一個先走n步,然後一起走

List tailN(List a, int n)
{
    List quick = a;
    List slow = a;
    for(int i = 0; i < n; i++)
    {
        quick = quick->next;
    } 
    while(quick != NULL)
    {
        quick = quick->next;
        slow = slow->next;
    }
    return slow;
}

 

4.兩邊微調:有序陣列找到兩個數的和

比如: 一個遞增序列中,找到兩個數的和為xx,返回他們的座標

思路:由於是遞增的,因此使用兩個指標,一個左邊i一個右邊j,小於xx則讓i向右,大於xx則讓j向左。

Result sumExist(int a[],int n, int sum)
{
	int i = 0, j = n - 1;
	Result result;
	while(i < j)
	{
		if(a[i] + a[j] < sum)
			i++;
		else if (a[i] + a[j] > sum)
			j--;
		else
			result.add(i);
			result.add(j);
			return result;	
	}
	return NULL;
}