線性表:具有相同數據類型的n(n>0)個數據元素的有限序列。
主要有順序存儲和鏈式存儲。
順序存儲:
特點:地址連續,隨機/存取,順序存儲。
建立:首地址/存儲空間大小(數組),表長。
方式:靜態和動態。
優點:存儲密度大;隨機存儲:快速存取表中任一位置元素。
缺點:插入刪除移動大量元素;對存儲空間要求高,會產生存儲空間的碎片。
1.插入
bool ListInsert(SqList &L,int i,Elemtype e){ if(i<1||i>L.length+1) //判斷i范圍是否有效 return false; if(L.length>=MaxSize) //當前存儲已滿,不能插入 return false; for(int j=L.length;j>=i;j--) //第i個元素后移 L.data [j]=L.data[j-1]; L.data[i-1]=e; //第i個元素放入e L.length++; //鏈表長度加1 return true; }
最好的情況:表尾插入 只用加一個數據,時間復雜度為o(1);
最壞的情況:表頭插入,所有元素后移一位,時間復雜度為o(n);
平均時間復雜度:o(n)。
2.刪除
bool ListDelete(SqList &L,int i,Elemtype &e){ if(i<1||i>L.length) //判斷i范圍是否有效 return false; e=L.data[i-1]; //將被刪元素賦給e for(int j=i;j<L.length;j++) //第i個后元素前移 L.data [j-1]=L.data[j]; L.length--; //鏈表長度減1 return true; }
時間復雜度如插入,但是具體要分析。
線性表鏈式存儲
通過一組任意的存儲單元來存儲線性表中的數據元素。為了建立起數據元素之間的線性關系,對每個鏈表結點,除了自身信息,還存放了一個指向其后繼的指針。
單鏈表:單個指針
typedef struct LNode{ //定義單鏈表結點類型 Elemtype data; //數據域 struct LNode *next; //指針域 }LNode,*LinkList;
通常用“頭指針”來標識一個單鏈表,如Linklist L,那么頭指針L就代指一個單鏈表。
單鏈表第一個結點之前附加一個結點,稱為“頭結點”。其數據域可不設任何信息,也可記錄表長等信息。頭結點指針域指向線性表第一個元素結點。
頭結點:操作方便:第一元素前插入和刪除元素和第一結點操作與其他結點一致;鏈表無論空或不空,操作也統一。
頭指針始終指向鏈表的第一個結點。
雙鏈表:雙指針
typedef struct DNode{ //定義單鏈表結點類型 Elemtype data; //數據域 struct DNode *prior,*next; //前驅指針和后繼指針 }DNode,*DLinkList;
插入:
給插入的前一個元素加輔助指針p,插入元素加輔助指針s
1.s->next=p->next;
2.p->next->prior=s;
3.s->prior=p;
4.p->next=s;;
刪除:
刪除的前一個元素加一個輔助指針p,刪除的指針加一個輔助指針q
1.p->next=q->next;
2.q->next->prior=p;
3.free(q);
循環單鏈表:
與單鏈表的區別在於,表中最后一個結點的指針不是NULL,而是改為指向頭結點,從而整個鏈表形成一個環。
從任何一個結點出發都能訪問到鏈表的每一個元素。
1.判斷條件:頭結點的后繼指針是否等於頭指針。
2.可對循環單鏈表不設頭指針而僅設尾指針,使效率更高。
循環雙鏈表:區別於雙鏈表是首尾結點構成環。
1.尾結點后繼指針指向表頭結點,頭結點的前驅指針指向尾結點。
2.當為空表時,頭結點的prior域和next域都等於L。
靜態鏈表:
借助數組來描述線性表的鏈式存儲結構,結點也有數據域data和指針域next,此指針是結點的相對地址(數值下標),又稱游標。
對插入與刪除操作與動態鏈表(動態分配內存的方式)相同,只需修改指針,而不需移動元素。