零個或多個數據元素的有限序列數組
- 有序性:元素之間是有順序的,若元素存在多個,則第一個元素無前驅,最後一個元素無後繼,其餘每一個元素都有且只有一個前驅和後繼。
- 有限性:線性表元素的個數n(n≥0)定義爲線性表的長度,當n=0時,稱爲空表。
- 同類型
ADT 線性表(List) Data Operation InitList(*L) 初始化操做,創建一個空的線性表L。 LIstEmpty(L) 若線性表爲空,返回true,不然返回false。 ClearList(*L) 將線性表清空。 GetElem(L,i,*e) 在線性表L中的第i個位置元素值返回給e。 LocateElem(L,e) 在線性表L中查找與給定值e相等的元素,若是查找成功,返回該元素在表中序號表示成功;不然,返回0表示失敗。 ListInsert(*L,i,*e) 在線性表L中的第i個位置插入新元素e。 ListDelete(*L,i,*e) 刪除線性表L中第i個位置元素,並用e返回其值。 ListLength(L) 返回線性表L的元素個數。 endADT
- 是用一段地址連續的存儲單元依次存儲線性表的數據元素。
- 經過佔位的形式,把必定內存空間給佔了,而後把相同數據類型的數據元素依次存放在這塊空地中。用一維數組來實現順序存儲結構,即把第一個數據元素存到數組下標爲0的位置中,接着把線性表相鄰的元素存儲在數組中相鄰的位置。
- 爲了創建一個線性表,要在內存中找一塊地,因而這塊地的第一個位置就很是關鍵,它是存儲空間的起始位置。
- 存儲空間的起始位置:數組data,它的存儲位置就是存儲空間的存儲位置
- 線性表的最大存儲容量:數組長度MaxSize
- 線性表的當前長度:length
線性表的長度是線性表中數據元素的個數,在任意時刻,線性表的長度≤數組的長度
#define MAXSIZE 20 //存儲空間初始分配量 typedef int ElemType; //ElementType類型根據實際狀況而定,這裏假設爲int typedef struct { ElemType data[MAXSIZE]; //數組存儲數據元素,最大值是MAXSIZE int length; //線性表當前長度 } *Sqlist;
int InitList(SqList *L) { (*L)=(SqList)malloc(sizeof(SqList)); (*L)->length=0; //空表長度爲0 return 1; }
int ListInsert(SqList L,int i,ElemType e){ int k; if(L->length==MAXSIZE){ //順序線性表已滿 return 0; } if(i<1 || i>L->length+1){ //當i不在範圍內時 return 0; } if(i<=L->length){//若插入數據位置不在表尾 for(k=L->length-1;k>=i-1;k--){ //將要插入位置後數據元素向後移動一位 L->data[k+1]=L->data[k]; } } L->data[i-1]=e; //新元素插入 L->length++; //表長+1 return 1; }
int ListDelete(SqList L,int i,ElemType e){ int k; if(L->length==0){ //線性表爲空 return 0; } if(i<1 || i>L->length){ //刪除位置不正確 return 0; } e=L->data[i-1]; if(i<L->length){ //若是刪除不是最後位置 for(k=i;k<L->length;k++){ //將刪除位置後繼元素前移 L->data[k-1]=L->data[k]; } } L->length--; //表長-1 return 1; }
int GetElem(SqList L,int i,ElemType e){ if(L.length==0 || i<1 || i>L.length){ return 0; } e=L.data[i-1]; return 1; }
int ListTraverse(SqList L) { int i,len; len=L->length; for(i=1;i<=len;i++){ printf("位置:%d,元素:%d\n",i,L->data[i-1]); } return 1; }
#include <stdio.h> #include <stdlib.h> #define MAXSIZE 20 //存儲空間初始分配量 typedef int ElemType; //ElementType類型根據實際狀況而定,這裏假設爲int typedef struct { ElemType data[MAXSIZE]; //數組存儲數據元素,最大值是MAXSIZE int length; //線性表當前長度 } *SqList; /*初始化順序結構*/ int InitList(SqList *L) { (*L)=(SqList)malloc(sizeof(SqList)); (*L)->length=0; //空表長度爲0 return 1; } /*插入元素*/ int ListInsert(SqList L,int i,ElemType e){ int k; if(L->length==MAXSIZE){ //順序線性表已滿 return 0; } if(i<1 || i>L->length+1){ //當i不在範圍內時 return 0; } if(i<=L->length){//若插入數據位置不在表尾 for(k=L->length-1;k>=i-1;k--){ //將要插入位置後數據元素向後移動一位 L->data[k+1]=L->data[k]; } } L->data[i-1]=e; //新元素插入 L->length++; //表長+1 return 1; } /*刪除元素*/ int ListDelete(SqList L,int i){ int k; if(L->length==0){ //線性表爲空 return 0; } if(i<1 || i>L->length){ //刪除位置不正確 return 0; } if(i<L->length){ //若是刪除不是最後位置 for(k=i;k<L->length;k++){ //將刪除位置後繼元素前移 L->data[k-1]=L->data[k]; } } L->length--; //表長-1 return 1; } /*得到元素*/ int GetElem(SqList L,int i){ if(L->length==0 || i<1 || i>L->length){ return 0; } printf("%d\n",L->data[i-1]); return 1; } /*打印順序結構*/ int ListTraverse(SqList L) { int i,len; len=L->length; for(i=1;i<=len;i++){ printf("位置:%d,元素:%d\n",i,L->data[i-1]); } return 1; } int main(void) { SqList L; InitList(&L); ListInsert(L,1,1); ListInsert(L,2,2); ListTraverse(L); GetElem(L,2); ListDelete(L,2); ListTraverse(L); return 0; }
- 頭指針是指鏈表指向第一個結點的指針,若鏈表有頭結點,則是指向頭結點的指針
- 不管鏈表是否爲空,頭指針均不爲空
- 頭指針是鏈表的必要元素
- 頭結點是爲了操做的統一和方便而設立的,放在第一元素的結點以前,其數據域通常無心義(也可存放鏈表的長度)
- 有了頭結點,對在第一元素結點前插入結點和刪除第一結點,其操做與其它結點的操做就統一了
- 頭結點不必定是鏈表必需要素
typedef int ElemType; typedef struct Node{ ElemType data; struct Node *next; } Node; typedef struct Node *LinkList;
int InitList(LinkList *L) { (*L)=(LinkList)malloc(sizeof(Node)); (*L)->next=NULL; return 1; }
int ListInsert(LinkList L,int i,ElemType e) { int j; LinkList p,s; p=L; j=1; while (p && j<i){ //尋找第i結點 p=p->next; ++j; } if(!p || j>i){ return 0; //第i個元素不存在 } s=(LinkList)malloc(sizeof(Node)); //生成新結點(C語言標準函數) s->data=e; //結構體即scanf s->next=p->next; //將p的後繼結點賦值給s的後繼 p->next=s; //將s賦值給p的後繼 return 1; }
int ListDelete(LinkList L,int i,ElemType e) { int j; LinkList p,q; p=L; j=1; while(p->next && j<i){ //歷尋找第i個元素 p=p->next; ++j; } if (!(p->next) || j>i){ return 0; //第i個元素不存在 } q=p->next; p->next=q->next; //將q的後繼賦值給p的後繼 e=q->data; //將q結點中的數據給e free(q); //讓系統回收此結點,釋放內存 return 1; }
int GetElem(LinkList L,int i,ElemType e){ int j; LinkList p; //聲明一結點p p=L->next; //讓p指向鏈表L的第一個結點 j=2; //j爲計數器 while(p && j<i){ //p不爲空或者計數器j尚未等於i時,循環繼續 p=p->next; //讓p指向下一個結點 ++j; } if(!p || j>i){ return ERROR; //第i個元素不存在 } e=p->data; //取第i個元素的數據 return 1; }
第一部分遍歷查找第i個結點;第二部分插入和刪除結點函數
int ClearList(LinkList L) { LinkList p,q; p=L->next; //p指向第一個結點 while(p){ //沒到表尾 q=p->next; free(p); p=q; } L->next=NULL; //頭結點指針域爲空 return 1; }
int ListTraverse(LinkList L){ LinkList e; int i=1; e=L; if(e->next==NULL){ return 0; } else{ while(e->next!=NULL){ printf("%d",i,e->next->data); e=e->next; i++; } return 1; } }
只有初始化的時候函數是帶*的spa
#include <stdio.h> #include <stdlib.h> #include <string.h> /*定義元素類型*/ typedef struct{ char name[20]; char press[20]; char writer[20]; char date[15]; double money; }Book; typedef Book ElemType; /*定義鏈表結構*/ typedef struct Node{ ElemType data; struct Node *next; } Node; typedef struct Node *LinkList; /*初始化鏈表*/ int InitList(LinkList *L) { *L=(LinkList)malloc(sizeof(Node)); (*L)->next=NULL; return 1; } /*借書*/ int ListDelete(LinkList L,char find[]) { int j; LinkList p,q; p=L; j=1; int a=0; if(p->next==NULL){ printf("\n對不起,圖書館暫無圖書,請先添加!\n"); return 0; } else{ while(p!=NULL){ if(strcmp(p->next->data.name,find)==0){ q=p->next; p->next=q->next; free(q); printf("\n刪除%s成功!\n",find); a=1; break; } p=p->next; } } if(a==0) printf("\n輸入的書名有誤,刪除失敗!\n"); } /*添書、還書*/ int ListInsert(LinkList L,int i) { int j; LinkList p,s; p=L; j=1; while (p && j<i){ //尋找第i結點 p=p->next; ++j; } if(!p || j>i){ return 0; //第i個元素不存在 } s=(LinkList)malloc(sizeof(Node)); //生成新結點(C語言標準函數) printf("\n請輸入書名:"); scanf("%s",s->data.name); printf("\n請輸入做者:"); scanf("%s",s->data.writer); printf("\n請輸入出版社:"); scanf("%s",s->data.press); printf("\n請輸入日期:"); scanf("%s",s->data.date); printf("\n請輸入價格:"); scanf("%lf",&s->data.money); s->next=p->next; //將p的後繼結點賦值給s的後繼 p->next=s; //將s賦值給p的後繼 return 1; } /*查書*/ int findbook(LinkList L){ LinkList e; int key; int sign=0; char find[20]; e=L; printf("\n請選擇你要查詢的關鍵詞種類:一、書名 二、做者 三、出版社 四、日期\n"); scanf("%d",&key); switch(key){ case 1: printf("\n請輸入您要查詢的書名:"); scanf("%s",find); while(e->next!=NULL){ if(strcmp(e->next->data.name,find)==0){ printf("\n符合條件書的信息:\n書名:%s 做者:%s 出版社:%s 日期:%s 價格:%.2lf\n",e->next->data.name,e->next->data.writer,e->next->data.press,e->next->data.date,e->next->data.money); sign=1; } e=e->next; } break; case 2: printf("請輸入您要查詢的做者:"); scanf("%s",find); while(e->next!=NULL){ if(strcmp(e->next->data.writer,find)==0){ printf("\n符合條件書的信息:\n書名:%s 做者:%s 出版社:%s 日期:%s 價格:%.2lf\n",e->next->data.name,e->next->data.writer,e->next->data.press,e->next->data.date,e->next->data.money); sign=1; } e=e->next; } break; case 3: printf("\n請輸入您要查詢的出版社:"); scanf("%s",find); while(e->next!=NULL){ if(strcmp(e->next->data.press,find)==0){ printf("\n符合條件書的信息:\n書名:%s 做者:%s 出版社:%s 日期:%s 價格:%.2lf\n",e->next->data.name,e->next->data.writer,e->next->data.press,e->next->data.date,e->next->data.money); } e=e->next; } break; case 4: printf("\n請輸入您要查詢的類日期:"); scanf("%s",find); while(e->next!=NULL){ if(strcmp(e->next->data.date,find)==0){ printf("\n符合條件書的信息:\n書名:%s 做者:%s 出版社:%s 日期:%s 價格:%.2lf\n",e->next->data.name,e->next->data.writer,e->next->data.press,e->next->data.date,e->next->data.money); sign=1; } e=e->next; } break; } return sign; } /*顯示*/ int ListTraverse(LinkList L){ LinkList e; int i=1; e=L; if(e->next==NULL){ return 0; } else{ while(e->next!=NULL){ printf("\n第%d本書的信息:\n書名:%s\t\t做者:%s\t\t出版社:%s\t\t日期:%s\t\t價格:%.2lf\n\n",i,e->next->data.name,e->next->data.writer,e->next->data.press,e->next->data.date,e->next->data.money); e=e->next; i++; } return 1; } } int main(void) { /*構造線性表 */ LinkList books; InitList(&books); int n,insert,loc,sign; char key[20]; do{ printf("\n--------------------------------ZUST圖書管理系統歡迎您-----------------------------------\n"); printf("\n請選擇功能:\n\n0、添加圖書\t一、查詢圖書\t二、刪除圖書\t三、全部圖書\t四、退出\n\n請輸入您要進行的操做:"); scanf("%d",&n); printf("\n-----------------------------------------------------------------------------------------\n"); switch(n){ case 0: printf("\n請輸入您要添加書的位置:"); scanf("%d",&loc); insert=ListInsert(books,loc); if(insert==0) printf("\n位置輸入有誤,添加失敗!\n"); break; case 1: sign=findbook(books); if(sign==0) printf("\n對不起,圖書館暫無此書!\n"); break; case 2: printf("\n請輸入您要刪除的圖書書名:"); scanf("%s",key); ListDelete(books,key); break; case 3 : ListTraverse(books); break; } }while(n!=4); printf("\n圖書管理系統已退出!\n"); return 0; }
- 將單鏈表中終端結點的指針端由空指針改成指向頭結點,就使整個單鏈表造成一個環,行成頭尾相接的單鏈表。
- 其實循環鏈表和單鏈表的主要差別就在於循環的判斷條件上,原來是判斷p->next是否爲空,如今則是p->next不等於頭結點,則循環未結束。
typedef struct DulNode { ElemType data; struct DulNode *prior; struct DulNode *next; } DulNode,*DuLinkList;
s->prior=p; //S的前驅 s->next=p->next; //S的後繼 p->next=prior=s; //後結點的前驅 p->next=s; //後結點的後繼
p->prior->next=p->next; //前結點的後繼 p->next->prior=p->prior; //後結點的前驅 free(p);
- 若線性表須要頻繁查找,不多進行插入和刪除操做時,宜採用順序存儲結構。
- 若須要頻繁插入和刪除時,宜採用單鏈表結構。
- 當元素個數變化較大或者根本不知道有多大時,用單鏈表結構。
- 事先知道線性表的大體長度,用順序存儲結構。