中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

單向鏈表 c語言實現

發布時間:2020-07-14 10:57:39 來源:網絡 閱讀:10126 作者:onecan2009 欄目:編程語言
  1. 定義(引用百度百科)
    單鏈表是一種鏈式存取的數據結構,用一組地址任意的存儲單元存放線性表中的數據元素。鏈表中的數據是以結點來表示的,每個結點的構成:元素(數據元素的映象) + 指針(指示后繼元素存儲位置),元素就是存儲數據的存儲單元,指針就是連接每個結點的地址數據。
  2. 場景

在實際生產中,有可能在軟件啟動后,對一些數據進行多態擴容,比如,網卡收發包的時候,從協議棧上產生一個需求的包,需要暫時排隊,等網卡把數據發送出去后,在在隊列里處理,所以這種利用堆中分散的內存,以結點為單位的數據結果是有一定的意義的。

  1. C語言實現,聊作記錄

鏈表的數據的數據結構

typedef struct node
{
        int data;                                           //數據域
        struct node *next;                          //指針域
}NODE_t;

鏈表的創建

    NODE_t *CreatNodeList()
{
    NODE_t *head = NULL;

    head = (NODE_t *)malloc(sizeof(NODE_t));
    if(!head)
        exit(-1);
    head->next = NULL;

    return head;
}

鏈表的插入,頭插入,有個頭節點,方便遍歷,處理

int InsertNode(NODE_t *head,int data)
{
    NODE_t *cur = NULL;

    if(!head)
        exit(-1);

    cur = (NODE_t *)malloc(sizeof(NODE_t));
    if(!cur)
        exit(-1);

    cur->data = data;
    //cur 插入到 head 和 head->next 之間
    cur->next = head->next;
    head->next = cur;

    return 0;
}

結點的查找

NODE_t *findNode(NODE_t *head,int data)
{
    head = head->next;
    while(head)
    {
        if(head->data == data)
        {
            break;
        }
        head = head->next;
    }
    if(head == NULL)
    {
        printf("sorry,%d is not in the list\n",data);
    }

    return head;
}

結點的刪除

    int DeleteNodeOfList(NODE_t *head,NODE_t *pfind)
{
    // 首先找到這個需要刪除指針的前一個節點的指針
    // 因為pfind 的合法性在外面判斷,此處不再判斷
    while(head->next != pfind)
    {
        head = head->next;
    }

    head->next = pfind->next;
    free(pfind);
    pfind = NULL;

    return 0;
}

這里的刪除,假設結點數目很多,則會造成一個問題,單鏈表只能一個方向,則需要找到需要刪除的節點的前驅指針,則需要從頭開始遍歷,比較浪費資源,所以,這個地方存在優化空間,就是,一旦擁有需要刪除的節點,則可以這么操作

  • 將需要刪除節點后驅結點的數據域數據拷貝至當前的刪除節點數據域
  • 刪除刪除節點的后驅指針

優化版本如下:

// 優化點: 不必每次都遍歷所有的節點,找到前驅節點
// 將這個需要刪除的節點的后驅節點的數據域拷貝過來,然后刪除這個后驅節點
int DeleteNodeOfList_Better(NODE_t *head,NODE_t *pfind)
{
    NODE_t *p = pfind->next;

    //最后一個節點,它其后沒有后驅節點,所以需要從頭遍歷,找到它的前置節點
    if(pfind->next == NULL)
    {
        while(head->next != pfind)
        {
            head = head->next;
        }

        head->next = pfind->next;
        free(pfind);
        pfind = NULL;
    }
    else //對于除最后一個節點的外的其他位置節點,則使用覆蓋后刪除后置節點的方式實現刪除
    {

        pfind->data = pfind->next->data;
        pfind->next = pfind->next->next;

        free(p);
        p = NULL;
    }

    return 0;
}

一旦找到結點的指針操作只是針對數據域的一個操作,比較便捷
結點的修改

int UpdateNode(NODE_t *head,int olddata,int newdata)
{
    NODE_t *p = findNode(head,olddata);
    if(p)
    {
        p->data = newdata;
    }

    return 0;
}

遍歷打印顯示

void showList(NODE_t *head)
{
    head = head->next;
    while(head)
    {
        printf("%d ==> ",head->data);
        head = head->next;
    }
    printf("end..\n");
}

鏈表的排序

int sortList(NODE_t *head)
{
    int i = 0,j = 0;
    int listlen = 0;
    int tmpData = 0;
    NODE_t *p = NULL;

    // 使用冒泡排序,不動指針域,比較數據域,使用臨時變量,將有大小之別的節點的數據域交換
    // 得到鏈表長度,方便冒泡
    listlen = ListNodeLen(head);

    // 指到首節點
    p = head->next;
    for(i = 0;i < listlen-1;i++)
    {
        // 每一輪從頭開始
        p = head->next;
        for(j = 0;j<listlen - i-1;j++)
        {
            // 將小值排在前面
            if(p->data > p->next->data)
            {
                tmpData = p->data;
                p->data = p->next->data;
                p->next->data = tmpData;
            }
            p = p->next;
        }
    }

    return 0;
}

這里只是demo,鏈表的數據域很小,所以這種排序方式可以,但是當數據域的很大時,直接使用這種排序,涉及到大量的搬運內存,將會導致很大的資源消耗,所以這個地方是存在優化的空間的,比如直接改變需要交換結點的指向關系
代碼如下

int sortList_better(NODE_t *head)
{
    // 當數據域很大的時候,搬遠數據很耗費資源,但是指針就4個字節,
    // 所以改變指針域的相互指向,就可解決問題
    // 思路如下:
    // 還是使用冒泡比較,當需要交換時,將兩個節點的指針域指向關系互換

    int i = 0,j = 0;
    int listlen = 0;
    NODE_t *p = NULL;
    NODE_t *q = NULL;
    NODE_t *tmp = NULL;
    listlen = ListNodeLen(head);

    for(i = 0;i <listlen -1;i++)
    {
        tmp = head;
        p = head->next;
        q = p->next;                    // q 永遠指向p結點的下一個結點
        for(j = 0;j <listlen-i-1;j++)
        {
            if(p->data > q->data)
            {
                //                NODE_t *tmp = prePointerOfNode(head,p);
//                現在有三個結點,prep p    q 他們分別代表的含義是

//                p 為當前結點
//                prep為p結點的前驅結點
//                q 為p結點的后續結點

//                現在需要將p 和 q的順序做對調,只需要改變其指向關系即可
//                1. 將prep 的下一個結點指向到q
//                2. 將p結點后續結點指向q的后續結點
//                3. 在第二步里已經在q的后續結點的已經找到,所以這個時候將q的后續結點指向p,
//                這樣子,就將p和q的順序對調過了
                tmp->next = q;
                p->next = q->next;
                q->next = p;

//                因為p和q的順序已經對調過了,為保證順序,將p和q的順序做一次對調,
//                確保q是p的下一個結點
                /*
                    注意p和q都是臨時變量,所以,這個地方并非對結點的對調,只是臨時指針的對調,就是將q對于結點的指針放到p這個臨時變量里
                    ,原來p對應的結點指針放到q這個臨時變量中
                */
                NODE_t *t = NULL;
                t = p;
                p = q;
                q = t;
            }
//            向下走一個
            tmp = tmp->next;
            p = p->next;
            q = p->next;
        }
    }

    return 0;
}

鏈表的逆序

void ReverseList(NODE_t *head)
{
    //將頭指針和其他鏈表割裂,這樣子就是一個空鏈表 和一個無頭的鏈表
    // 然后將另一個鏈表的每個結點拆出來,然后使用頭插法插入到空鏈中,這樣子最后就實現了鏈表的逆向排序

    NODE_t *HeadNextNode = head->next;
    head->next = NULL; //分割鏈表,分成一個空鏈和一個鏈表

    // 將第二個鏈表的每一個結點分別插入到空鏈的頭部
    for(HeadNextNode;HeadNextNode !=NULL;HeadNextNode = HeadNextNode->next)
    {
        InsertNode(head,HeadNextNode->data);
    }
}

這個思路很好,不易出錯,如果貿然的從指向關系上入手,很容易把自己繞暈

鏈表的銷毀

void DestoryNodeList(NODE_t *head)
{
    NODE_t *p = NULL;

    while(head)
    {
        p = head->next;
        free(head);
        head = p;
    }
}
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

若羌县| 新兴县| 安陆市| 葫芦岛市| 闽清县| 临海市| 冀州市| 平罗县| 大渡口区| 濉溪县| 顺义区| 信宜市| 双辽市| 兴宁市| 和田县| 邢台市| 新建县| 盐边县| 武胜县| 新竹市| 承德县| 枞阳县| 高尔夫| 额尔古纳市| 辽源市| 离岛区| 蓝田县| 筠连县| 永福县| 临漳县| 湄潭县| 宁陵县| 长沙县| 游戏| 佳木斯市| 冀州市| 彩票| 浦城县| 色达县| 巴彦县| 南川市|