線性表

1. 線性表綜述:
線性表是具有相同特性數據元素的一個有限序列
該序列中所包含元素的個數叫做線性表的長度
當一個線性表有序時,成爲有序表,屬於邏輯結構
線性表的邏輯特徵:
對於至少含有一個元素的線性表來說
除起始元素沒有前驅元素外,其他元素都有一個唯一前驅
除終端元素沒有後繼元素外,其他元素都有一個唯一後繼
在線性表中,每個元素最多隻有一個前驅和後繼元素
線性表存儲結構:
線性表有順序和鏈式兩類存儲結構,前者成爲順序表,後者成爲鏈表
順序表特點:
無需爲元素間的邏輯關係兒增加額外的存儲空間
可以隨機存取表中的任何一個元素,但是要佔用連續的空間
而且插入和刪除元素時需要移動大量的元素,平均需要移動n/2個元素
鏈表特點:
不僅存儲每個節點的信息,而且也存儲節點之間的關係(通過指針)
鏈表的地址可以是不連續的,不支持隨機訪問,插入和刪除比較快
鏈表中的第一個節點的存儲位置通常被成爲頭指針
如果鏈表有頭結點,頭指針爲頭結點的地址
如果沒有頭結點,頭指針爲開始節點的地址
通常用頭指針來標識一個鏈表
1、順序表程序:

//線性表存儲空間的初始分配量 
#define LIST_INIT_SIZE 10
//順序存儲結構的分配增量 
#define LIST_INCREMENT 5
typedef int ElemType;
//順序存儲結構體
struct SqList
{
    ElemType* elem;     //存儲空間基址
    int length;         //數據元素當前長度 
    int listsize;       //當前分配的總容量(元素個數) 
};
/*******基礎操作********/
//初始化順序表
void InitList(SqList* L)
{
    L->elem = (ElemType*)malloc(sizeof(ElemType)*LIST_INIT_SIZE); 
    if (L->elem == NULL)
    {
        printf("空間申請失敗!\n");
        exit(-1); 
    }
    L->length = 0;
    L->listsize = LIST_INIT_SIZE;
}
//銷燬順序表
void DestroyList(SqList* L)
{
    free(L->elem);
    L->elem = NULL;
    L->length = 0;
    L->listsize = 0; 
}
//清空順序表
void ClearList(SqList* L)
{
    L->length = 0;
}
//判空
int EmptyList(SqList* L)
{
    if (L->length == 0)
        return 1;
    return 0; 
}
//順序表長
int ListLength(SqList* L)
{
    return L->length;
}
//得到順序表第index元素
int GetElem(SqList* L, int index, ElemType* e)
{
    //要找的元素不在順序表範圍內 
    if (index<1 || index>L->length) 
        return -1;
    *e = L->elem[index-1];
    return 1; 
}
//返回元素的位置
int LocateElem(SqList* L, ElemType* e)
{
    for (int i=0; i<L->length; ++i)
    {
        //元素相等 
        if (L->elem[i] == *e) 
            return i;
    }
    return -1;
}
//返回元素的前驅
int PriorElem(SqList* L, ElemType* e)
{
    int index = LocateElem(L, e);
    //第一個元素沒有前驅 
    if (index == -1 || index == 0)
        return -1;
    return index-1; 
}
//返回元素的後繼
int NextElem(SqList* L, ElemType* e)
{
    int index = LocateElem(L, e);
    //最後一個元素沒有後繼 
    if (index == -1 || index == L->length-1)
        return -1;
    return index+1; 
}
//順序表插入
int ListInsert(SqList* L, int index, ElemType* e)
{
    //判斷插入位置是否合法
    if (index<1 || index>L->listsize)
        return -1; 
    //判斷空間是否滿
    if (L->length == L->listsize)
    {
        L->elem = (ElemType*)realloc(L->elem, (L->listsize+LIST_INCREMENT)*sizeof(ElemType)); 
        if (L->elem == NULL)
            exit(-1); 
        L->listsize += LIST_INCREMENT;
    }
    //開始插入
    for (int i=L->length-1; i>=index-1; --i)
    {
        //循環後移 
        L->elem[i+1] = L->elem[i]; 
    }
    //插入 
    L->elem[index-1] = *e; 
    //長度++
    L->length++; 

    return 1;
}
//順序表刪除
int ListDelete(SqList* L, int index)
{
    //判斷刪除位置是否合法
    if (index<1 || index>L->length)
        return -1;
    //開始刪除
    for (int i=index-1; i<L->length; ++i)
    {
        L->elem[i] = L->elem[i+1]; 
    }
    --L->length;

    return 1;
}
//順序表遍歷
void ListTraverse(SqList* L)
{
    for (int i=0; i<L->length; ++i)
    {
        cout << L->elem[i] << ' '; 
    }
    cout << endl;
}
/*******進階操作********/
//合併兩個順序表
//將所有在順序表Lb中,但不在La中的元素插入到La中 
void Union(SqList* La, SqList* Lb)
{
    int lena = ListLength(La);
    int lenb = ListLength(Lb); 
    for (int i=0; i<Lb->length; ++i)
    {
        //在La中沒有出現就插入 
        if (LocateElem(La, &(Lb->elem[i])) == -1) 
            ListInsert(La, La->length+1, &(Lb->elem[i]));       
    }
}
//歸併兩個有序順序表
void MergeList(SqList* La, SqList* Lb, SqList* Lc) 
{
    int i=0, j=0;
    int lena = La->length;
    int lenb = Lb->length;
    //初始化順序表Lc 
    InitList(Lc); 

    //兩個都沒有完的時候 
    while (i<lena & j<lenb)
    {
        //La<Lb
        if (La->elem[i] < Lb->elem[j]) 
        {
            //尾插La裏面的元素 
            ListInsert(Lc, Lc->length+1, &(La->elem[i])); 
            ++i;
        }
        else    //Lb<La
        {
            //尾插Lb裏面的元素 
            ListInsert(Lc, Lc->length+1, &(Lb->elem[j])); 
            ++j;
        }
    }
    //其中有一個插完了
    while (i < lena)
    {
        //尾插La裏面的元素 
        ListInsert(Lc, Lc->length+1, &(La->elem[i])); 
        ++i;
    }
    while (j < lenb)
    {
        //尾插Lb裏面的元素 
        ListInsert(Lc, Lc->length+1, &(Lb->elem[j])); 
        ++j;
    }
}

int main()
{
    /*基礎操作測試 
    SqList L;
    //初始化 
    InitList(&L);
    cout << "初始化後: 首地址:" << L.elem << "元素個數:" << L.length << "總容量:" << L.listsize << endl;
    //頭插
    for (int i=1; i<=5; ++i)
         ListInsert(&L, 1, &i); 
    cout << "頭插5次:" << endl; 
    ListTraverse(&L);
    //是否爲空
    cout << "順序表是否爲空:" << EmptyList(&L) << endl; 
    //大小
    cout << "順序表大小:" << ListLength(&L) << endl; 
    //清空順序表
    cout << "清空順序表:" << endl;
    ClearList(&L);
    cout << "清空後大小:" << ListLength(&L) << endl; 
    //尾插
    for (int i=6; i<=10; ++i)
        ListInsert(&L, L.length+1, &i);
    cout << "尾插5次:" << endl; 
    ListTraverse(&L);
    //刪除第3個元素 
    cout << "刪除第3個元素:" << endl;
    ListDelete(&L, 3);
    cout << "刪除後:" << endl; 
    ListTraverse(&L); 
    //銷燬順序表
    DestroyList(&L); 
    cout << "首地址:" << L.elem << "元素個數:" << L.length << "總容量:" << L.listsize << endl;
    cout << "順序表已成功銷燬" << endl; 
    */

    SqList La, Lb, Lc;
    //初始化 
    InitList(&La);
    InitList(&Lb);
    InitList(&Lc); 
    //插入La 
    for (int i=1; i<=5; ++i)
         ListInsert(&La, La.length+1, &i);
    //插入Lb
    for (int i=2; i<=10; i+=2) 
        ListInsert(&Lb, Lb.length+1, &i);
    //合併兩個順序表
    //Union(&La, &Lb); 
    //遍歷順序表La
    //cout << "合併後爲:" << endl; 
    //歸併La和Lb
    MergeList(&La, &Lb, &Lc); 
    cout << "La和Lb歸併後:" << endl; 
    ListTraverse(&Lc); 

    return 0;
}

2.鏈表:
和順序表相比,鏈表在實現插入、刪除操作時,不需要移動大量的元素
但是不容易實現隨機存取,適用於經常進行插入和刪除的線性表
一般用一個頭指針來唯一的標識一個鏈表
鏈表的插入和刪除:
插入和刪除要先把後邊的鏈表鏈起來,然後再鏈接上前面的鏈表,都要找到當前節點和前驅
鏈表的插入和刪除主要考慮:第一個元素、中間元素、最後一個元素
其中,中間元素和最後一個元素的操作都相同,只剩下第一個元素和其餘元素的區別
會因爲帶頭結點和不帶頭結點而有所區別:比較重要:
不帶頭結點:
因爲如果不帶頭結點插入表頭或者刪除表頭的話,得修改鏈表的唯一標識指針即 L
帶頭結點的話,令頭結點爲第0個元素,表頭結點爲第1個元素
就可以不用修改L來插入或者刪除表頭了,這時修改的是頭結點的指針域
鏈表指針始終指向的是頭結點。所以就不用考慮插入是在表頭還是在其他地方了
帶頭結點:
帶頭結點的鏈表的插入和刪除,都是定義兩個結點指針變量 p=L, q=NULL
p指向要插入或刪除的結點,q指向p的前驅結點
因爲不管是插入和刪除,都要找到待操作結點和該結點的前驅
插入和刪除:
插入:位置判斷條件是:pos<1 || NULL==q 就退出
因爲插入時,可以插在1–length+1之間,即 p==NULL是允許的
刪除:位置判斷條件是:pos<1 || NULL==p 就退出
因爲在刪除時,可以刪除1–length之間,要刪除的結點必須不能爲空,即 p!=NULL

typedef int ElemType;
//鏈表結構體定義 
typedef struct Node
{
    ElemType data;      //數據域
    struct Node* next;  //指針域 
}Node, *LinkList;

//初始化
//也可以用Node** L來代替LinkList* L 
void InitList(LinkList* L)
{
    //產生頭結點,並使L指向該頭結點
    *L = (Node*)malloc(sizeof(Node)); 
    if (*L == NULL)
    {
        cout << "分配失敗!" << endl; 
        exit(-1); 
    }
    (*L)->next = NULL; 
}
//銷燬鏈表
//得傳入一個鏈表的指針 
void DestroyList(LinkList* L)
{
    Node* q = NULL;

    while (NULL != *L)
    {
        q = (*L)->next;
        free(*L);
        *L = q; 
    }
    cout << "銷燬成功!" << endl; 

}
//清空一個鏈表,不改變頭結點 
void ClearList(LinkList L)
{
    Node* p = NULL;
    Node* q = NULL;
    p = L->next;        //p指向第一個結點 

    while (NULL != p)   //循環刪除鏈表結點 
    {
        q = p->next;
        free(p);
        p = q; 
    }
    L->next = NULL;
}
//鏈表判空
int ListEmpty(LinkList L)
{
    if (L->next == NULL)
        return 1;
    return 0; 
}
//統計鏈表長度
int ListLength(LinkList L)
{
    Node* q = L->next;
    int length = 0;

    while (NULL != q)
    {
        ++length;
        q = q->next;
    }

    return length;
}
//取得鏈表第i個元素
int GetElem(LinkList L, int pos, ElemType* e)
{
    Node* p = L->next;
    int count = 1;

    while (NULL != p && count < pos)
    {
        ++count;
        p = p->next;
    }
    //沒有找到 
    if (NULL==p || count>pos) 
        return 0;
    //找到 
    *e = p->data;
    return 1;
}
//獲取元素在鏈表中的位置
int LocateElem(LinkList L, ElemType* e)
{
    Node* p = L->next;  //使p指向第一個結點
    int pos = 1;

    while (NULL!=p && p->data!=(*e))
    {
        ++pos;
        p = p->next;
    }
    if (NULL == p)
        return -1;
    return pos; 
}
//找元素的前驅
int PriorElem(LinkList L, ElemType* cur_e, ElemType* pre_e)
{
    Node* p = L->next;      //指向當前結點 
    Node* q = NULL;         //指向當前結點的前驅 

    while (NULL!= p && p->data!=(*cur_e))
    {
        q = p;
        p = p->next;
    }
    if (NULL == p)
        return -1;
    *pre_e = q->data;
    return 1; 
}
//找到元素的後繼
int NextElem(LinkList L, ElemType* cur_e, ElemType* next_e) 
{
    Node* p = L->next;  

    while (p->next != NULL && p->data!=(*next_e)) 
    {
        p = p->next;
    }
    if (NULL == p->next)        //沒有找到 
        return -1; 
    *next_e = p->next->data;
    return 1;
}
//在指定位置插入
//可以在1和length+1位置之間進行插入 
int ListInsert(LinkList L, int pos, ElemType* e)
{
    Node* p = L;            //指向要插入的位置
    Node* q = NULL;         //指向要插入的前驅
    int count = 0; 
    //尋找要插入結點的前驅q
    while (NULL!=p && count<pos)
    {
        q = p;
        p = p->next;
        ++count;
    }
    //插入位置不對 大於表長NULL==p或者小於1 
    if (pos<1 || NULL==q) 
    {
        cout << "插入位置不正確!" << endl; 
        return -1; 
    }
    p = (Node*)malloc(sizeof(Node));
    p->data = *e; 
    p->next = q->next;
    q->next = p;

    return 1;
}
//在指定位置刪除元素
//在1和length之間可以刪除 
int ListDelete(LinkList L, int pos, ElemType* e)
{
    Node* p = L;            //指向要刪除的位置 
    Node* q = NULL;         //指向要刪除位置的前驅 
    int count = 0;

    while (NULL!=p && count<pos)
    {
        q = p;
        p = p->next;
        ++count;
    }
    if (pos<1 || NULL==p)   //位置不在範圍內
    { 
        cout << "刪除位置不正確!" << endl; 
        return -1;
    }
    //刪除結點 
    q->next = p->next;
    *e = p->data;
    free(p);
    p = NULL;

    return 1;
}
/***********不帶頭結點的鏈表的插入和刪除***********/
int ListInsert(LinkList* L, int pos, ElemType* e)
{
    int count = 1;  
    Node* p = NULL;
    Node* q = NULL;
    p = (Node*)malloc(sizeof(Node));
    p->data = *e;
    p->next = NULL;
    //表頭
    if (pos == 1)
    {
        p->next = (*L);
        *L = p; 
    }
    else        //其他位置 
    {
        while (NULL!=q && count<pos-1) 
        {
            q = q->next;
            ++count;
        }
        //插入位置大於表長 
        if (pos<1 || NULL == q) 
        {
            cout << "插入位置不對!" << endl;
            return -1; 
        }
        p->next = q->next;
        q->next = p;
    }

    return 1;
}
int ListDelete(LinkList* L, int pos, ElemType* e)
{
    Node* p = *L;
    Node* q = NULL;
    int count = 1;
    //頭刪 
    if (pos == 1)
    {
        p = (*L)->next;
        *L = p->next;
        free(p);
        p = NULL; 
    }
    else
    {
        while (NULL!=p && count<pos)
        {
            q = p;
            p = p->next;
            ++count;
        }
        if (pos<1 || NULL==p) 
        {
            cout << "插入位置不合法!" << endl; 
            return -1;
        }
        q->next = p->next;
        *e = p->data;
        free(p);
        p = NULL; 
    }
}

//鏈表遍歷
void ListTraverse(LinkList L)
{
    Node* p = L->next;
    while (NULL != p)
    {
        cout << p->data << endl;
        p = p->next;
    }
}
//頭插建立鏈表
void HeadCreateList(LinkList* L, int n) 
{
    //建立頭結點
    *L = (Node*)malloc(sizeof(Node));
    (*L)->next = NULL; 
    Node* p = NULL;
    int num = 0;

    for (int i=0; i<n; ++i)
    {
        p = (Node*)malloc(sizeof(Node));
        cin >> num;
        p->data = num;
        p->next = (*L)->next;
        (*L)->next = p; 
    }
}
//尾插法建立鏈表
void TailCreateList(LinkList* L, int n)
{
    //建立頭結點 
    (*L) = (Node*)malloc(sizeof(Node));
    (*L)->next = NULL;
    Node* p = NULL;
    Node* cur = *L;
    int num = 0;

    for (int i=0; i<n; ++i)
    {
        //找到尾結點
        while (NULL != cur->next)
        {
            cur = cur->next;
        }
        //開闢新結點
        p = (Node*)malloc(sizeof(Node)); 
        cin >> num;
        p->data = num;
        p->next = NULL;
        //插入尾部
        cur->next = p; 
    }
}

//合併兩個鏈表(合併不同元素)
void Union(LinkList La, LinkList Lb)
{
    ElemType e;
    int len_a = ListLength(La);
    int len_b = ListLength(Lb);
    for (int i=1; i<=len_b; ++i)
    {
        GetElem(Lb, i, &e);
        if (LocateElem(La, &e) == -1) 
            ListInsert(La, ++len_a, &e); 
    }
}
//歸併兩個有序鏈表
void MergeList(LinkList La, LinkList Lb, LinkList Lc)
{
    int len_a = ListLength(La);
    int len_b = ListLength(Lb);
    int i=1, j=1;
    Node* pa = La->next;
    Node* pb = Lb->next;
    Node* pc = NULL;

    while (i<=len_a && j<=len_b)
    {
        //La < Lb
        if (pa->data < pb->data)
        {
            //開闢新結點 
            pc = (Node*)malloc(sizeof(Node));
            pc->data = pa->data;
            pc->next = NULL;
            //接入Lc
            Lc->next = pc;
            Lc = pc;
            //La後移一個
            pa = pa->next;
            ++i;
        }
        else
        {
            //開闢新結點
            pc = (Node*)malloc(sizeof(Node));
            pc->data = pb->data;
            pc->next = NULL;
            //接入Lc
            Lc->next = pc;
            Lc = pc;
            //Lb後移一個
            pb = pb->next;
            ++j; 
        }
    }
    while (i <= len_a)
    {
        //開闢新結點
        pc = (Node*)malloc(sizeof(Node));
        pc->data = pa->data;
        pc->next = NULL;
        //接入Lc
        Lc->next = pc;
        Lc = pc;
        //後移一個
        pa = pa->next;
        ++i;
    }
    while (j <= len_b)
    {
        //開闢新結點
        pc = (Node*)malloc(sizeof(Node)); 
        pc->data = pb->data;
        pc->next = NULL;
        //接入Lc
        Lc->next = pc;
        Lc = pc;
        //後移一個
        pb = pb->next;
        ++j; 
    }
}

int main()
{
    /****基礎功能測試****/
    /*
    LinkList L;
    //初始化鏈表 
    InitList(&L);  
    //頭插
    for (int i=0; i<5; ++i)
        ListInsert(L, 1, &i);
    //在第最後一個位置插入
    int num = 10;
    ListInsert(L, 6, &num);
    //遍歷
    cout << "插入後的鏈表:" << endl; 
    ListTraverse(L); 
    //鏈表長度
    cout << "鏈表長度爲:" << ListLength(L) << endl; 

    //在第1個位置刪除
    cout << "刪除後的鏈表:" << endl; 
    ListDelete(L, 1, &num);
    //遍歷
    ListTraverse(L); 

    //清空鏈表
    cout << "清空鏈表:" << endl; 
    ClearList(L); 
    //遍歷
    ListTraverse(L);
    //鏈表長度
    cout << "鏈表長度爲:" << ListLength(L) << endl; 

    //銷燬鏈表
    cout << "銷燬鏈表:" << endl;
    DestroyList(&L); 
    */

    LinkList L;
    //頭插創建鏈表 
    //HeadCreateList(&L, 3); 
    //尾插創建鏈表 
    TailCreateList(&L, 3); 
    //遍歷
    ListTraverse(L);

    /****進階功能測試****/
    LinkList La, Lb, Lc;
    //初始化鏈表 
    InitList(&La);  
    InitList(&Lb);  
    InitList(&Lc); 
    //頭插
    for (int i=1; i<=5; ++i)
        ListInsert(La, i, &i);
    //尾插 
    int count = 1;
    for (int i=2; i<=10; i+=2)
        ListInsert(Lb, count++, &i);
    //遍歷
    ListTraverse(La); 
    ListTraverse(Lb); 
    //Union(La, Lb); 
    cout << "歸併後的鏈表爲:" << endl; 
    MergeList(La, Lb, Lc); 
    ListTraverse(Lc);

    return 0;
}
發佈了73 篇原創文章 · 獲贊 107 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章