數據結構之單向鏈表02

今天的訓練題目是,帶頭單向鏈表的操作
1.帶頭單向鏈表建立
2.帶頭單向鏈表節點添加
3.帶頭單向鏈表節點刪除
4.帶頭單向鏈表數據排序
5.兩個帶頭遞減單向鏈表合併成一個鏈表
6.帶頭/不帶頭單向鏈表的倒序

=================================================================
單鏈表操作
NOTE:包括插入,刪除,排序,倒序等
=================================================================


1.單項鍊表建立:

typedef struct Node_t {
     int data;
     struct Node_t *next;
}NODE_T;

/* 帶頭的單項鍊表 */
NODE_T *Init_list(int len)
{
     NODE_T *head;
     NODE_T *p1, p2;
     int err = 0;
     int n;
     head = (NODE_T *)malloc(sizeof(struct Node_t));
     if (!head) {
         fprintf(stderr, "Create link list head failed\n");
         return NULL;
     }
     p1 = head;
     while (len--) {

         p2 = (struct Node_t *)malloc(sizeof(struct Node_t));
         if (!p2) {
             err++;
             break;
         }
         p1->next = p2;
         p1 = p1->next;

     }
     p1->next = NULL;

     /* free memory if malloc failed */
     while (err--) {
         p1 = head;
         n = err;
         while (n--) {
             p2 = p1->next;
             p1 = p2;
         }
         free(p1);
         p1 = NULL;
     }

     return head;
}
==========================================================
獲取第i個元素,單向鏈表不支持隨機讀取,必須從頭指針開始遍歷
==========================================================
/**
* @brief get_link_list
*
* @param link
* @param i 1 <= i <= 表長,if i == 0,return list head
*
* @return
*/
NODE_T *get_link_list(NODE_T *link, int i)
{
     NODE_T *head, p;

     if (!link)
         return NULL;

     head  = link;

     while (i-- && head != NULL) {
         p = head->next;
         head = p;
     }

     return head;
}

============================================================
在第cursor節點之前插入節點,data域爲value, 插入位置大於1,
必須在頭指針以後, 0節點是頭頭節點
============================================================
/**
* @brief insert_linklist
*
* @param link
* @param cursor    1 <= cursor <= 表長
* @param value
*
* @return
*/
int insert_linklist(NODE_T *link, int cursor, int value)
{
     NODE_T *head, *p;
     int i;

     if (!link)
         return -1;

     head = link;
     i = 0;

     while (head != NULL && i < cursor-1) {
         head = head->next;
         i++;
     }

     p = (NODE_T * )malloc(NODE_T);
     if (p == NULL)
         return -1;
     p->next = head->next
     p->data = value;

     head->next = p;

     return 0;
}

=======================================================
刪除節點操作,不允許刪除鏈表頭,需要先找到刪除節點的前驅節點
比如刪除第二個節點,需先找到第一個節點(節點計數從非頭節點開始)
=======================================================
int delete_linklist(NODE_T *head, int cursor)
{
     NODE_T *p, p1;
     int i = 0;

     if (!head)
         return -1;
     p = head;

     while (p->next != NULL && i < cursor-1)    {
         p = p->next;
         i++;
     }

     if (p->next == NULL) /* the end */
         fprintf(stderr, "No this position\n");
     else {
         p1 = p->next;
         p->next = p->next->next;
         free(p1);
     }

     return 0;

}
========================================================
帶頭單向鏈表的排序
使用冒泡法,遞減排序
========================================================
#define SWAP(a,b)    {a = a + b; \
             b = a - b;    \
             a = a - b;}
int sort_list(NODE_T *head)
{
     NODE_T *p1, p2;
     int n, len = 0;

     if (!head)
         return -1;
     /* calc list length */
     p1 = head->next;
     while (p1 != NULL) {
         len++;
         p1 = p1->next;
     }

     while (len--) {

         p1 = head->next;

         /* no compare list head, compare count = len(no head) - 1 */
         n = len - 1;
         while (p1 != NULL && n--) {
             p2 = p1->next;
             if (p1->data <= p2->data)
                 SWAP(p1->data, p2->data);
             p1 = p2;
         }
     }

     return 0;
}

==========================================================
兩個帶頭的遞減鏈表,合併成一個遞減的鏈表
==========================================================
NODE_T *merge_linklist(NODE_T *la, NODE_T *lb)
{
     NODE_T *pa, *pb, *pc;

     if (!la || !lc)
         return NULL;

     lc = la; /* 以la節點頭作爲合併後節點頭 */

     pa = la->next;
     pb = lb->next;
     pc = lc;

     while (pa != NULL && pb != NULL) {
         if (pa->data >= pb->data) {
             pc->next = pa;
             pc = pa;
             pa = pa->next;
         }
         else {
             pc->next = pb;
             pc = pb;
             pb = pb->next;
         }
     }

     /* 連接pa或pb中剩餘的節點 */
     if (pa != NULL)
         pc->next = pa;
     else
         pc->next = pb;

     return lc;
}

=============================================================
單項鍊表的倒序
=============================================================
基本思路有兩種
1.遍歷整個鏈表,將數據提取出來,然後在逆向賦值給鏈表各節點
這需要至少遍歷兩次鏈表,並且用於存儲數據的數組,需要提前申請(沒遍歷
之前鏈表節點數量位置,則該數組大小不確定,是否應足夠大),並且只是
數據倒序了,鏈表結構並沒有倒序
2.逆向操作鏈表,即把第一個節點,作爲最後一個,並依次倒置

下面描述第二種,區別帶頭節點和不帶節點
帶頭單向鏈表的倒序
---------------------


不帶頭單向鏈表倒序
---------------------
NODE_T *reverse_link(NODE_T *head)
{
     NODE_T *pn, *pt;
     NODE_T *pr = NULL;

     if (!head)
         return NULL;

     pn = head; /* no list head */

     while (pn != NULL) {
         pt = pn->next;
         pn->next = pr;
         pr = pn;
         pn = pt;
     }

     return pr;

}

帶頭單向鏈表倒序, 頭節點不變
---------------------------------
NODE_T *reverse_link(NODE_T *head)
{
     NODE_T *pn, *pt, ph;
     NODE_T *pr = NULL;

     if (!head)
         return NULL;

     ph = head;
     pn = head->next;

     while (pn != NULL) {
         pt = pn->next;
         pn->next = pr;
         pr = pn;
         pn = pt;
     }

     ph->next = pr;

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