1、假設一個線性表採用順序表表示,設計一個算法,刪除其中所有值等於x的元素,要求算法的時間複雜度爲O(n),空間複雜度爲O(1)。
解:這裏提供兩種解法:
解法一:
設刪除L中所有值等於x元素後的順序表爲L1,顯然L1包含在L中,爲此L1重用L的空間。掃描順序表L,重建L中只包含不等於x的元素,算法過程是置k=0(k用來記錄新表中的元素個數),用i從左到右掃描L中所有的元素,當i指向的元素爲x時跳過它;否則將其放置在k的位置,即 L->data[k]=L->data[i] , k++。
算法如下:
void delnodel(SqList * &L,ElemType x)
{
int k,i; //k記錄不等於x的元素個數
for(i=0;i<L->length;i++)
{
if(L->data[i]!=x)
{
L->data[k]=L->data[i];
k++;
}
}
L->length=k;
}
解法二:
掃描順序表L,用i從左到右掃描L中的所有元素,用k記錄L中當前等於x的元素的個數,一邊掃描L一邊統計當前k的值,當i指向的元素爲x時k增加1;否則將不爲x的元素前移k個位置,即L->data[i-k]=L->data[i]。最後修改L的長度。算法如下:
void delnode2(SqList * &L,ElemType x)
{
int k=0,i=0;
while(i<L->length)
{
if(L->data[i]==x)
k++;
else
L->data[i-k]=L->data[i];
i++;
}
L->length=L->length-k;
}
2、有一個順序表L,假設元素類型ElemType爲整型,設計一個儘可能高效的算法,以第一個元素爲分界線,將所有小於等於它的元素移到該基準的前面,將所有大於它的元素移到該基準的後面。
解法一:
用pivot存放基準,i(初值爲0)從左到右掃描,j(初值爲L->length-1)從右到左掃描。當i!=j時循環(即循環到i和j指向同一元素時爲止):j從右到左找一個小於等於pivot的元素data[j],i從左到右找一個大於pivot的元素data[i],然後將data[i]和data[j]進行交換。當循環結束後再將data[0]和data[i]進行交換,算法如下:
int partition1(SqList * &L)
{
int i=0,j=L->length;
ElemType pivot=L->data[0]; //以data[0]爲基準
while(i<j) //從區間兩端交替向中間掃描,直到i=j
{
while(i<j && L->data[j]>pivot) //從右到左掃描,找到一個小於等於pivot的元素
j--;
while(i<j && L->data[i]<=pivot) //從左到右掃描,找到一個大於pivot的元素
i++;
if(i<j)
swap(L->data[i],L->data[j]); //將找到的這兩個元素進行交換
}
swap(L->data[i],L->data[0]);
}
有些讀者有可能看不明白,我用圖表來展示一下該算法的執行過程。
解法二:
用pivot存放基準,i(初值爲0)從左到右查找,j(初值爲L->length-1)從右到左查找。當i不等於j時循環:j從右向左找一個小於等於pivot的data[j],找到後將data[j]放到data[i]處(用data[j]覆蓋data[i]),i從右向左找一個大於pivot的元素data[i],找到後將data[j]放到data[j]處(用data[i]覆蓋data[j])。最後讓data[i]=pivot。算法如下:
void partition2(SqList * &L)
{
int i=0,j=L->length-1;
ElemType pivot=L->data[0];
while(i<j) //從區間兩端交替向中間掃描,直到i=j
{
while(i<j && L->data[j]>pivot) //從右到左掃描,找到一個小於等於pivot的元素
j--;
L->data[i]=L->data[j];
while(i<j && L->data[i]<=pivot) //從左到右掃描,找到一個大於pivot的元素
i++;
L->data[j]=L->data[i];
}
l->data[i]=pivot;
}