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;
}