【數據結構】第二章 線性表

1 線性表的概念

(1) 定義

零個或多個數據元素的有限序列數組

(2) 屬性

  • 有序性:元素之間是有順序的,若元素存在多個,則第一個元素無前驅,最後一個元素無後繼,其餘每一個元素都有且只有一個前驅和後繼。
  • 有限性:線性表元素的個數n(n≥0)定義爲線性表的長度,當n=0時,稱爲空表。
  • 同類型

2 線性表的抽象數據類型

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

3 線性表的順序存儲結構

(1) 定義

  • 是用一段地址連續的存儲單元依次存儲線性表的數據元素。
  • 經過佔位的形式,把必定內存空間給佔了,而後把相同數據類型的數據元素依次存放在這塊空地中。用一維數組來實現順序存儲結構,即把第一個數據元素存到數組下標爲0的位置中,接着把線性表相鄰的元素存儲在數組中相鄰的位置。
  • 爲了創建一個線性表,要在內存中找一塊地,因而這塊地的第一個位置就很是關鍵,它是存儲空間的起始位置。

(2) 三個屬性

  • 存儲空間的起始位置:數組data,它的存儲位置就是存儲空間的存儲位置
  • 線性表的最大存儲容量:數組長度MaxSize
  • 線性表的當前長度:length
    線性表的長度是線性表中數據元素的個數,在任意時刻,線性表的長度≤數組的長度

clipboard.png

(3) 結構代碼

#define MAXSIZE 20 //存儲空間初始分配量
typedef int ElemType; //ElementType類型根據實際狀況而定,這裏假設爲int
typedef struct
{
    ElemType data[MAXSIZE]; //數組存儲數據元素,最大值是MAXSIZE
    int length; //線性表當前長度
} *Sqlist;

(4) 操做

A 初始化順序結構

int InitList(SqList *L)  
{
    (*L)=(SqList)malloc(sizeof(SqList));
    (*L)->length=0; //空表長度爲0
    return 1;  
}

B 插入

clipboard.png

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

C 刪除

clipboard.png

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

D 得到元素

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

E 打印元素

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

(5) 實例

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

4 線性表的鏈式存儲結構

(1) 定義

clipboard.png

clipboard.png

A 頭指針

  • 頭指針是指鏈表指向第一個結點的指針,若鏈表有頭結點,則是指向頭結點的指針
  • 不管鏈表是否爲空,頭指針均不爲空
  • 頭指針是鏈表的必要元素

B 頭結點

  • 頭結點是爲了操做的統一和方便而設立的,放在第一元素的結點以前,其數據域通常無心義(也可存放鏈表的長度)
  • 有了頭結點,對在第一元素結點前插入結點和刪除第一結點,其操做與其它結點的操做就統一了
  • 頭結點不必定是鏈表必需要素

clipboard.png

(2) 結構代碼

typedef int ElemType;
typedef struct Node{
    ElemType data;
    struct Node *next;
} Node;
typedef struct Node *LinkList;

(3) 操做

A 初始化鏈式結構

int InitList(LinkList *L)
{
    (*L)=(LinkList)malloc(sizeof(Node));
    (*L)->next=NULL;
    return 1;
}

B 插入

clipboard.png

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

C 刪除

clipboard.png

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

D 得到元素

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個結點;第二部分插入和刪除結點函數

E 整表刪除

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

F 打印元素

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

(4) 實例

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

5 循環鏈表

(1) 定義

  • 將單鏈表中終端結點的指針端由空指針改成指向頭結點,就使整個單鏈表造成一個環,行成頭尾相接的單鏈表。
  • 其實循環鏈表和單鏈表的主要差別就在於循環的判斷條件上,原來是判斷p->next是否爲空,如今則是p->next不等於頭結點,則循環未結束。

(2) 雙向鏈表

A 結構代碼

typedef struct DulNode
{
    ElemType data;
    struct DulNode *prior;
    struct DulNode *next;    
} DulNode,*DuLinkList;

B 操做

  • a 插入
s->prior=p; //S的前驅
s->next=p->next; //S的後繼
p->next=prior=s; //後結點的前驅
p->next=s; //後結點的後繼
  • b 刪除
p->prior->next=p->next; //前結點的後繼
p->next->prior=p->prior; //後結點的前驅
free(p);

6 單鏈表結構與順序存儲結構優缺點

  • 若線性表須要頻繁查找,不多進行插入和刪除操做時,宜採用順序存儲結構。
  • 若須要頻繁插入和刪除時,宜採用單鏈表結構。
  • 當元素個數變化較大或者根本不知道有多大時,用單鏈表結構。
  • 事先知道線性表的大體長度,用順序存儲結構。

7 線性表的關係

clipboard.png

相關文章
相關標籤/搜索