數據結構:順序表圖解及c代碼

在這裏插入圖片描述
順序表思想
定義了一個順序表的結構體,存放了它的長度,容量信息,還有申請的存結點的內存的首地址。

結構體中定義的是一個二級指針,申請的內存是存放傳入結點的指針。

內存管理方面:順序表管理指表內存和指針數組內存。
結點的內存由上層自己負責。

seqlist.h

#ifndef SEQLIST_H
#define SEQLIST_H

typedef void SeqList;
typedef void SeqListNode;

SeqList* SeqList_Create(int capacity);

void SeqList_Destroy(SeqList* list);

void SeqList_Clear(SeqList* list);

int SeqList_Length(SeqList* list);

int SeqList_Capacity(SeqList* list);

int SeqList_Insert(SeqList* list, SeqListNode *node,int pos);

SeqListNode* SeqList_Get(SeqList *list,int pos);

SeqListNode* SeqList_Delete(SeqList* list ,int pos);

#endif // SEQLIST_H
typedef void SeqList;
typedef void SeqListNode;

傳給上層的是一個void類型,對於他們來說只是一個句柄,留給上層管理表的首地址以及結點地址。
上層測試中

Teacher* tmp = (Teacher *)SeqList_Get(list, i);

根據自己的業務來解析表傳來的結點地址

上層將順序表地址和結點地址傳給底層函數,底層函數知道具體類型是什麼,類型轉換後進行操作與處理。
所以在seqlist.c中,每個函數中都有兩句代碼。

  TSeqList *tlist = NULL;
  tlist = (TSeqList*)list;

seqlist.c

定義表的結構體

typedef struct _tag_SeqList
{
    int length;
    int capacity;
    unsigned int **node;
}TSeqList;

創建表時
1.要申請表的內存,內存清零
2.根據容量申請相應的內存來存放結點指針,node 是二級指針,node[i]是指針。
3.參數置初始狀態

SeqList* SeqList_Create(int capacity)
{
    int ret =0;
    TSeqList *tmp = NULL;
    tmp=(TSeqList*)malloc(sizeof(TSeqList));
    if(tmp == NULL)
    {
        ret = -1;
        printf("func SeqList_Create() err:create %d\n",ret);
        return NULL;
    }
    memset(tmp,0,sizeof(TSeqList));   //需要包含string.h頭文件
    tmp->node=(unsigned int **)malloc(sizeof(unsigned int *)*capacity);
    //這裏順序表只是存了結點的地址以保證能訪問,但是不把節點數據及內存併入順序表中
    //這樣順序表只管理自己申請的這倆內存,而節點的內存還是由上層管理
    //這也是destroy中只用釋放申請的tlist->node及tlist本身的內存
    if(tmp->node == NULL)
    {
        ret = -2;
        printf("func SeqList_Create() err:malloc %d\n",ret);
        return NULL;
    }
    tmp->capacity = capacity;
    tmp->length = 0;
     return tmp;
}

順序表銷燬時要釋放內存
順序表清空時主要是長度要置零以重新存數據。
這裏可加memset? 我覺得是要加,主動清零內存

void SeqList_Destroy(SeqList* list)
{
    TSeqList *tlist = NULL;
    if(list == NULL)
    {
        return ;
    }
    tlist = (TSeqList*)list;
    if(tlist->node!=NULL)
    {
        free(tlist->node);
    }
    free(tlist);
    return;

}
void SeqList_Clear(SeqList* list)
{
     TSeqList *tlist = NULL;
     if(list == NULL)
     {
        return ;
     }
     tlist= (TSeqList*)list;
     //memset(tlist->node,0,sizeof(unsigned int *)*tlist->capacity);
     tlist->length = 0;
     return;
}

獲取長度和容量沒什麼,返回數據就可以

int SeqList_Length(SeqList* list)
{
    TSeqList *tlist = NULL;
    if(list == NULL)
    {
        return -1;
    }
    tlist = (TSeqList*)list;
    return tlist->length;
}
int SeqList_Capacity(SeqList* list)
{
    TSeqList *tlist = NULL;
    if(list == NULL)
    {
        return -1;
    }
    tlist = (TSeqList*)list;
    return tlist->capacity;
}

獲取結點也不涉及移動,直接返回相應位置的節點即可

SeqListNode* SeqList_Get(SeqList *list,int pos)
{
     int i =0,ret =0;
     TSeqList *tlist = NULL;
     SeqListNode *s_ret = NULL;
     if(list == NULL || pos <0)
     {
        ret = -1;
        printf("funt SeqList_Get() err %d\n",ret);
        return NULL;
     }
     tlist = (TSeqList*)list;
     s_ret =(SeqListNode*)tlist->node[pos];
     return s_ret;
}

插入和刪除一個是要移動, 二是要注意長度++或 - -,同時要判斷位置是否合法,判滿等。

int SeqList_Insert(SeqList* list, SeqListNode *node,int pos)
{
    int i =0,ret =0;
    TSeqList *tlist = NULL;
    if(list == NULL || node == NULL || pos <0)  //爲什麼不判pos>length呢? 因爲只要表沒滿,可以處理讓他插在最尾
    {
        ret = -1;
        printf("func SeqList_Insert() err %d\n",ret);
        return ret;
    }
    tlist = (TSeqList*)list;
    //先判滿
    if(tlist->length == tlist->capacity)
    {
        ret = -2;
        printf("func SeqList_Insert() (tlist->length == tlist->capacity) err: %d\n",ret);
        return ret;
    }
    //容錯修正
    if(pos>tlist->length)
    {
        pos = tlist->length;
    }
    //先後移元素
    for(i=tlist->length;i>pos;i--)
    {
        tlist->node[i]=tlist->node[i-1];
    }
    tlist->node[i] = node;
    tlist->length++;
    return 0;
}
SeqListNode* SeqList_Delete(SeqList* list ,int pos)
{
    int i=0;
    TSeqList *tlist = NULL;
    SeqListNode *ret = NULL;
    if(list == NULL || pos < 0)   //刪除位置大於表長度的情況如何處理,返回的是NULL
    //但存在clear後未覆蓋刪除原有數據的問題吧?所以應優化clear
    {
        printf("func SeqList_Delete() err");
        return NULL;
    }
    tlist = (SeqList*)list;
    ret = (SeqListNode*)tlist->node[pos];
    for(i=pos+1;i<tlist->length;i++)
    {
        tlist->node[i-1]=tlist->node[i];
    }
    tlist->length--;
     return ret;
}

插入操作時要先判滿和容錯修正,然後移動,再插入
刪除操作時先緩存要彈出的結點,再移動。返回結點

測試用例

    ret = SeqList_Insert(list, (SeqListNode*)&t5, 0);  //頭插法

    for (int i = 0; i < SeqList_Length(list); i++)
    {
    Teacher* tmp = (Teacher *)SeqList_Get(list, i);
        if (tmp == NULL)
        {
            return;
        }
        printf("tmp->age:%d", tmp->age);
    }

一個是頭插法。 數據可以傳入結構體等類型
再一個是解析彈出的結點,根據上層的數據類型進行類型轉換後解讀。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章