學習了線性表之后發現刪除的方式有多種多樣,同時出題的方式也千奇百怪。
首先是最簡單的刪除:把要刪除元素之后的元素全部往前挪,將欲刪除的覆蓋掉。
但是這種刪除方式的局限性太大了,首先就是時間復雜度,這個算法的時間復雜度為O(n^2).

bool Delete( List L, Position P ) { int i; if(P>=L->Last||P<0) { printf("POSITION %d EMPTY",P); return false; } L->Last--;//這里的Last是指長度了 for(i=P;i<L->Last;i++) L->Data[i]=L->Data[i+1]; return true; }
這個算法遇到對時間有要求的情況基本就崩了。
例:
6-2 線性表元素的區間刪除(20 分)
給定一個順序存儲的線性表,請設計一個函數刪除所有值大於min而且小於max的元素。刪除后表中剩余元素保持順序存儲,並且相對位置不能改變。
函數接口定義:
List Delete( List L, ElementType minD, ElementType maxD );
其中List
結構定義如下:
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存線性表中最后一個元素的位置 */
};
L
是用戶傳入的一個線性表,其中ElementType
元素可以通過>、==、<進行比較;minD
和maxD
分別為待刪除元素的值域的下、上界。函數Delete
應將Data[]
中所有值大於minD
而且小於maxD
的元素刪除,同時保證表中剩余元素保持順序存儲,並且相對位置不變,最后返回刪除后的表。
裁判測試程序樣例:
#include <stdio.h>
#define MAXSIZE 20
typedef int ElementType;
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存線性表中最后一個元素的位置 */
};
List ReadInput(); /* 裁判實現,細節不表。元素從下標0開始存儲 */
void PrintList( List L ); /* 裁判實現,細節不表 */
List Delete( List L, ElementType minD, ElementType maxD );
int main()
{
List L;
ElementType minD, maxD;
int i;
L = ReadInput();
scanf("%d %d", &minD, &maxD);
L = Delete( L, minD, maxD );
PrintList( L );
return 0;
}
/* 你的代碼將被嵌在這里 */
輸入樣例:
10
4 -8 2 12 1 5 9 3 3 10
0 4
輸出樣例:
4 -8 12 5 9 10
由於這題有些函數需要裁判完成,我寫了一個能測試的main函數
復制過去就能在編譯器上測試了。

#include <stdio.h> #include <stdlib.h> #define MAXSIZE 20 typedef int ElementType; typedef int Position; typedef struct LNode *List; struct LNode { ElementType Data[MAXSIZE]; Position Last; /* 保存線性表中最后一個元素的位置 */ }; List Insert( List L, ElementType X, Position P ); List ReadInput(); /* 裁判實現,細節不表。元素從下標0開始存儲 */ void PrintList( List L ); /* 裁判實現,細節不表 */ List Delete( List L, ElementType minD, ElementType maxD ); List MakeEmpty(); int main() { List L; ElementType minD, maxD,N,X=0,P; int i; scanf("%d", &N); L=MakeEmpty(); while ( N-- ) { scanf("%d",&P); L=Insert(L, X, P); X++; } L->Last--; // for(i=0;i<L->Last;i++) // printf("%d ",L->Data[i]); scanf("%d %d", &minD, &maxD); L = Delete( L, minD, maxD ); for(i=0;i<=L->Last;i++) printf("%d ",L->Data[i]); return 0; } List MakeEmpty() { List ptr; ptr=(List)malloc(sizeof(struct LNode)); ptr->Last=0; return ptr; } List Insert( List L, ElementType X, Position P ) { if(!L)return false; int i=0; L->Data[X]=P; L->Last++; return L; } /*你的代碼插在這*/
這里有一個很重要的點這里的L->Last是下標!!!
此題有多種解法,我先列出三種
1.會超時的,也就是剛才的刪除法

List Delete( List L, ElementType minD, ElementType maxD ) { int i=0,j; if(!L)return L; if(minD>=maxD)return L; while(i<=L->Last) { if(L->Data[i]<maxD&&L->Data[i]>minD) { L->Last--; for(j=i;j<=L->Last;j++) { L->Data[j]=L->Data[j+1]; } } else i++; } return L; }
2.第二種算法的思路就是,建立一個輔助數組,將不想刪除的數記錄下來,遍歷完一次數組過后,在將數組的內容抄錄到線性表中,
同時L->Last的大小也變為不想刪除的數的個數。
雖然這算法使時間復雜度變為O(n)了,但是這種算法的局限性是多定義了一個數組,導致空間復雜度變大。

List Delete( List L, ElementType minD, ElementType maxD ) { int i=0,count=0; if(!L)return L; if(minD>=maxD)return L; int a[L->Last+1];//輔助數組 while(i<=L->Last) { if(L->Data[i]<=minD||L->Data[i]>=maxD) { a[count]=L->Data[i]; count++;//記錄個數 } i++; } L->Last=--count;//L->Last是下標,所以,減少一個 for(i=0;i<=count;i++) L->Data[i]=a[i]; return L; }
3.這是問其他人后得知的(感謝感謝他)
思路是:
遍歷一遍數組,遇到要刪除的元素把數量記錄下來,遇到不刪除的元素前移,覆蓋掉要刪除的元素。結束后整個長度剪掉刪除數就好了。
假定我需要刪除1 4中的元素(不包括1和4哦)
代碼:

List Delete( List L, ElementType minD, ElementType maxD ) { int i=0,count=0; if(!L)return L; if(minD>=maxD)return L; for(;i<=L->Last;i++) { if(L->Data[i]>minD&&L->Data[i]<maxD) count++;//計算數量 else L->Data[i-count]=L->Data[i];//往前挪動 } L->Last-=count;//長度變短 return L; }
還有兩題課后練習題,也挺有意思的。