線性表定義以及基本操作
定義
- 相同數據類型的n個數據元素組成的有限序列,n>=0
- 除第一個元素以外,每個元素有且只有一個直接前驅
- 除最後一個元素以外,每個元素有且只有一個直接後繼
- 線性表屬於邏輯結構
基本操作
- InitList ( &L ):初始化表,構造一個空的線性表
- Length ( L ):返回線性表L的長度
- LocateElem ( L , e ):按值查找
- GetElem ( L , i ):按位查找
- ListInsert( &L , i , e ):插入操作,在表L中第i個位置插入指定元素e
- ListDelete( &L , i , e ):刪除操作,刪除表L中第i個位置的元素,並用e返回刪除元素的值
- PrintList( L ):輸出操作,按照前後順序輸出線性表L中的元素
- Empty( L ):判空操作,空爲true,非空爲false
- DestroyLise( &L ):銷燬操作。銷燬線性表,並且釋放空間
1 順序表示
1.1 定義
- 順序存儲又稱爲順序表
- 用一組地址連續的存儲單元依次存儲線性表中的數據元素
- 邏輯上相鄰的兩個元素物理位置上也相鄰
- 邏輯順序與物理順序相同
- 最主要特點是隨機訪問
1.2 基本操作的實現
- 定義實現
- 靜態分配
#define MAXSIZE 1000
typedef struct
{
ElemType data[MAXSIZE];
int length;
}SqList;
- 動態分配
#define MAXSIZE 1000
typedef struct
{
ElemType *data;
int MaxSize,length;
}SqList
//C的初始動態分配語句
L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize);
//C++的初始動態分配語句
L.data=new ElemType[InitSize];
- 插入操作 O(n)
bool ListInsert(SqList &L,int i,ElemType e)
{
if(i<1||i>L.length+1) return false;//判定i的範圍是否有效
if(L.length>=MaxSize) return false;//判斷當前L的長度是否達到最大長度
for(int j=L.length-1;j>=i;j--)
{
L.data[j]=L.data[j-1];
}
L.data[i-1]=e;
L.length++;
return true;
}
- 刪除操作 O(n)
bool ListDelete(SqList &L,int i,ElemType &e)
{
if(i<1||i>L.length) return false;
e=L.data[i-1];
for(int j=i;i<L.length;j++)
{
L.data[j-1]=L.data[j];
}
return true;
}
- 按值查找 O(n)
- 從前往後依次遍歷即可
1.3 問題解決
- 設將n(n>1)個整數存放到一維數組中,將R中保存的序列循環左移P個位置,即將R中的數據由(1 2 3 4 5 6…n)變爲(3 4 5 6…n 1 2)
- 算法思想:分成兩段,分別顛倒,再將總序列顛倒
- 1 2 3 4 5 6 -> 2 1 6 5 4 3 -> 3 4 5 6 1 2
void Reverse(int R[],int from,int to)
{
int k;
for(int i=0;i<(to-from+1)/2;i++)
{
k=R[from+i];
R[from+i]=R[to-i];
R[to-i]=k;
}
}
void Converse(int R[],int n,int p)
{
Reverse(R,0,p-1);
Reverse(R,p,n-1);
Reverse(R,0,n-1);
}
- 給定一個長度爲n一維數組,尋找出現次數最多的元素
- 算法思想:利用map<int,int>存不同元素出現次數
int Search(int a[],int length)
{
map<int,int>m;
for(int i=0;i<length;i++)
{
++m[a[i]];
}
int value=(m.begin())->first;
int max=(m.begin())->second;
for(map<int,int>::iterator iter=m.begin();iter!=m.end();iter++)
{
if(iter->second>max)
{
value=iter->first;
max=iter->second;
}
}
return value;
}
2 鏈式表示
2.1 單鏈表
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
LinkList List_HeadInsert(LinkList &L)
{
LNode *s;
int k;
L=(LinkList)malloc(sizeof(LNode));//創建頭節點,並且分配內存
L->next=NULL;
cin>>k;
while(k!=9999)//選擇一個終止條件,這裏用x=9999來代替
{
s=(LNode*)malloc(sizeof(LNode));
s->data=k;
s->next=L->next;
L->next=s;
cin>>k;
}
return L;
}
- 尾插法 O(n)
LinkList list_TailInsert(LinkList &L)
{
LNode *s;
LNode *r=L;
int k;
L=(LinkList)malloc(sizeof(LNode));//創建頭節點,並且分配內存
L->next=NULL;
cin>>k;
while(k!=9999)//選擇一個終止條件
{
s=(LNode*)malloc(sizeof(LNode));
s->data=k;
s->next=r->next;
r->next=s;
r=s;
cin>>k;
}
return L;
}
- 按位查找(查找的是節點)
LNode *GetELem(LinkList L,int i)
{
int j=1;
LNode *p=L->next;
if(i==0)
return L;
if(i<1)
return NULL;
while(j<i&&p)
{
p=p->next;
j++;
}
return p;
}
- 按值查找(從頭遍歷,和上面差不多,方法定義的時候也是尋找節點)
- 插入節點(隨便想想啦,注意指針順序)
- 刪除節點(同上)
2.2 雙鏈表
- 擁有兩個指針,分別指向前驅節點和後驅節點
typedef struct DNode
{
Elemtype data;
struct Dnode *piror,*next;
}DNode.*Dlinklist;
2.3 循環鏈表
- 循環單鏈表
- 判空條件爲:L->next==L
- 循環雙鏈表
- 判空條件爲:L->next == L && L->piror == L
2.4 靜態鏈表
- 藉助數組來描述線性表的鏈式存儲結構
#define MaxSize 100
typedef struct
{
ElemType data; //保存數據
int next; //保存下一個節點的數組下標
}SLinkList[MaxSize];
+結束標誌爲:next==-1
順序表與鏈表的比較
- 總結一下大概就是順序表存取方便,鏈表操作方便