1. 程式人生 > >單向鏈表 c語言實現

單向鏈表 c語言實現

單鏈表 c 基本操作

  • 定義(引用百度百科)
    單鏈表是一種鏈式存取的數據結構,用一組地址任意的存儲單元存放線性表中的數據元素。鏈表中的數據是以結點來表示的,每個結點的構成:元素(數據元素的映象) + 指針(指示後繼元素存儲位置),元素就是存儲數據的存儲單元,指針就是連接每個結點的地址數據。
  • 場景
  • 在實際生產中,有可能在軟件啟動後,對一些數據進行多態擴容,比如,網卡收發包的時候,從協議棧上產生一個需求的包,需要暫時排隊,等網卡把數據發送出去後,在在隊列裏處理,所以這種利用堆中分散的內存,以結點為單位的數據結果是有一定的意義的。

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

    單向鏈表 c語言實現