1. 程式人生 > >資料結構之連結串列基本操作

資料結構之連結串列基本操作

涉及到單鏈表的基本操作有如下:

int initList(linkList *);  //初始化一個單鏈表,具有頭指標,頭結點,頭結點->next=NULL; int createListHead(linkList *, int n);  //頭插法建立一個連結串列,連結串列長度為n; int createListTail(linkList *, int n);  //尾插法建立一個連結串列,連結串列長度為n; int getlength(linkList *);  //獲取單鏈表的長度; int printList(linkList *);  //列印整個連結串列; int getElem(linkList *,int i,ElemType *);  //獲取連結串列中第i個位置處節點的資料元素; int insertList(linkList *, int i, ElemType data);  //在連結串列的指定位置(i節點)插入一個節點,i的範圍為1~length(連結串列總長度); int insertListTail(linkList *, ElemType data);  //給連結串列追加一個節點,在最末尾處增加; int deleteList(linkList *, int i, ElemType *data);  //刪除指定位置(i節點)處的節點,i的範圍為1~length(連結串列總長度); int clearList(linkList *);  //刪除整個連結串列,使頭結點->next=NULL;

(一)ADT:

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

(二)初始化:int initList(linkList *L)

int initList(linkList *L)
{
    (*L) = (linkList)malloc(sizeof(Node));
    (*L)->next = NULL;
    printf("連結串列初始化成功\n");
    return 1;
}

初始化一個指向頭節點的指標,使頭指標->next=NULL,頭指標->data不做處理;  

(三)建立一個單鏈表

int createListHead(linkList *L,int n) {
    linkList p;
    int i = 0;
    srand((int)time(0));
    for (i = 0; i < n; i++)
    {
        p= (linkList)malloc(sizeof(Node));
        p->data = rand() % 100;
        printf("testing:Node[%d]=%d\n",i+1,p->data);
        p->next = (*L)->next;
        (*L)->next = p;
    }
    printf("連結串列(頭插法)建立成功\n");
    return 1;
}

說明:

1、圖中的head表示頭指標,而在建立單鏈表中的入參phead是指向指標的指標;即*phead等同於head,*head指向頭節點;

2、初始化和建立整表的函式中,為什麼入參是linkList *型別的引數呢,為什麼不是Node *型別的;之前我的理解是可以使用Node*型別的入參,這樣宣告一個Node *head,這樣在建立整表的函式中可以直接createList(head,10),直接傳入頭指標,但是嘗試過以後,會在通過頭指標訪問各節點資料的時候,彈出錯誤視窗,原因還不太清楚;

3(補充)在看《C和指標》258的時候,看到了這麼一句話,好像可以解釋為什麼需要傳入連結串列的基本操作函式中的入參是一個指標型別的變數;

“i='a';*pi='a';**ppi='a';  //這三條語句具有同樣的效果;i-整型變數,pi-指向i的指標,ppi-指向pi指標的指標;

在一條簡單的對i賦值的語句就可以完成任務的情況下,為什麼還要使用更為複雜的涉及間接訪問的方法呢?這是因為簡單賦值並不總是可行,例如連結串列的插入。在那些函式中,我們無法使用簡單賦值,因為變數名在函式的作用域內部是未知的。函式所擁有的只是一個指向需要修改的記憶體位置的指標,所以要對該指標進行間接訪問操作以訪問需要修改的變數。

           

int createListTail(linkList *L, int n) {
    linkList p, temp;
    temp = (*L);
    int i;
    srand((int)time(0));
    for (i = 0; i < n;i++) {
        p = (linkList)malloc(sizeof(Node));
        p->data = rand() % 100;
        printf("testing:Node[%d]=%d\n", i + 1, p->data);
        p->next = NULL;
        temp->next = p;
        temp = p;
    }
    printf("連結串列(尾插法)建立成功\n");
    return 1;
}

 

(四)獲取連結串列的長度

int getlength(linkList *L) {
    linkList p;
    int length=0;
    p = (*L)->next;//p指向第一個節點;
    while (p) {
        length++;
        p = p->next;
    }
    return length;
}

 (五)列印整個連結串列

int printList(linkList *L) {
    linkList p;
    int i = 0;
    p = (*L)->next;//p指向第一個節點;
    printf("-----------列印整個連結串列-----------\n");
    if (p==NULL) {
        printf("這是一個空連結串列.\n");
    }
    while (p) {
        i++;
        printf("第%d個節點的資料data為=%d\n",i,p->data);
        p = p->next;
    }
    return 1;
}

(六)獲取指定位置處的節點元素;

int getElem(linkList *L, int i, ElemType *getdata) {
    linkList p;
    p = (*L)->next;
    if (p == NULL)
    {
        printf("連結串列為空,請建立一個連結串列\n");
        *getdata = -1;
        return 0;
    }
    if (i < 1)
    {
        printf("您所查詢的節點%d,應該大於0,請重新輸入查詢\n",i);
        *getdata = -1;
        return 0;
    }
    int j = 1;
    while (p&&j<i) {
        j++;
        p = p->next;
    }
    if (p == NULL)
    {
        printf("您所查詢的節點%d,已經超出了陣列的長度\n",i);
        *getdata = -1;
        return 0;
    }
    *getdata = p->data;
    printf("查詢成功!\n", i);
    return 1;
}

(七)插入節點;

插入節點分為兩種,一種是在連結串列的長度範圍內插入節點,第二種是在連結串列的尾部追加一個節點;

假設連結串列的長度為10,第一種可以在1-10位置處插入節點,比如在第10個位置插入一個節點,則原先的第10節點變為了11節點,但是第二種是所有節點位置都不變,在第11個位置追加一個新的節點;

int insertList(linkList *L, int i, ElemType data)
{
    linkList p;
    linkList insNode;
    p = (*L);
    int j=0;
    // 連結串列為空,在第1個位置插入一個新的節點;
    if (p ->next == NULL) {
        printf("連結串列為空,預設在第一個位置插入一個節點.\n");
        insNode = (linkList)malloc(sizeof(Node));
        insNode->data = data;
        insNode->next = p->next;
        p->next = insNode;
        printf("節點插入成功.\n");
        return 1;
    }
    // 連結串列非空的情況下,可以在i=1~length的位置插入節點,如果超過了連結串列的長度,就會提示錯誤;
    // 其實如果在length+1的位置處插入一個新節點,就相當於在尾部追加一個節點,在本函式中會報錯,可以單獨實現一個函式;
    while(p && j<i-1) 
    {
        j++;
        p = p->next;
        //printf("j=%d\tp->data=%d\n", j, p->data);
    }
    if (p->next==NULL) {
        printf("您要插入的位置,超過了連結串列的長度 %d,請重新操作!\n",j);
        return 0;
    }
    insNode = (linkList)malloc(sizeof(Node));
    insNode->data = data;
    insNode->next = p->next;
    p->next = insNode;
    
    printf("節點插入成功\n");
    return 1;
}

  追加節點;

int insertListTail(linkList *L, ElemType data)
{
    linkList temp;
    linkList p=(*L);
    while(p) {
        temp = p; 
        p = p->next;
    }
    p = (linkList)malloc(sizeof(Node));
    p->data = data;
    p->next = NULL;
    temp->next = p;
    printf("節點插入成功\n");
    return 1;
}

(八)刪除節點;

int deleteList(linkList *L, int i, ElemType *data)
{
    linkList p,pnext;
    int j = 0;
    p = (*L);
    if (p->next == NULL) {
        printf("連結串列為空,無法刪除指定節點.\n");
        *data = -1;
        return 0;
    }
    while (p->next && j<i-1) {
        j++;
        p = p->next;
        //printf("j=%d\t p->data=%d\n",j,p->data);
    }//條件最多定位到最後一個節點;
    if ( p->next == NULL) {
        printf("您要刪除的節點,超過了連結串列的長度 %d,請重新操作!\n", j);
        *data = -1;
        return 0;
    }
    pnext = p->next;
    p->next = pnext->next;
    *data = pnext->data;
    free(pnext);
    printf("節點刪除成功\n");
    return 1;
}

(九)刪除這個連結串列;

int clearList(linkList *L) {
    linkList p, temp;
    p = (*L)->next;//p指向第一個節點
    while (p) {
        temp = p;
        p = p->next;
        free(temp);
    }
    (*L)->next = NULL;
    printf("整個連結串列已經clear.\n");
    return 1;
}