【鏈表】單鏈表:不帶表頭結點

寫在前面的話:

  1. 版權聲明:本文爲博主原創文章,轉載請註明出處!
  2. 博主是一個小菜鳥,並且非常玻璃心!如果文中有什麼問題,請友好地指出來,博主查證後會進行更正,啾咪~~
  3. 每篇文章都是博主現階段的理解,如果理解的更深入的話,博主會不定時更新文章。
  4. 本文最後更新時間:2020.4.27

什麼是鏈表

鏈表是程序設計中一種重要的動態數據結構,它是動態地進行存儲分配的一種結構。

分爲三種:

  • 單鏈表
  • 循環鏈表
  • 雙向鏈表

動態性體現在:

  • 鏈表中的元素個數可以根據需要增加和減少,不像數組,在聲明之後就固定不變。
  • 元素的位置可以變化,即可以從某個位置刪除,然後再插入到一個新的地方。

結點裏的指針存放下一個結點的地址

  1. 鏈表中的元素稱爲“結點”,每個結點包括兩個域:數據域和指針域。
  2. 單向鏈表通常有一個頭指針(head),用於指向鏈表頭,也是指向鏈表在內存的首地址。
  3. 單向鏈表有一個尾結點,該結點的指針部分指向一個空節點(NULL)。

代碼示例

1. 定義鏈表的數據結構

/* =================
 定義鏈表數據結構
================= */
struct node
{
    int num;
    struct node *next;    //next存放下一個結點的地址
};

一個指針類型的成員既可指向其他類型的結構體數據,也可以指向自己所在的結構體類型的數據。

next 是 struct node 類型中的一個成員,它又指向 struct node 類型的數據。

2. 創建頭指針

#include <stdio.h>
#include <stdlib.h>

/* =================
 定義鏈表數據結構
================= */
struct node
{
    int num;
    struct node *next;    //next存放下一個結點的地址
};

typedef struct node Node;
typedef Node * Link;

/* ===================
 功能:初始化頭指針
 返回:void
=================== */
void init_head_node(Link *head)
{
    *head = NULL;           //頭指針置空
}

int main()
{
    Link head;           //創建頭指針
    init_head_node(&head);  //初始化頭指針

    return 0;
}

3. 插入節點

3.1 頭插

從鏈表的頭部插入新的節點。

#include <stdio.h>
#include <stdlib.h>

/* =================
 定義鏈表數據結構
================= */
struct node
{
    int num;
    struct node *next;    //next存放下一個結點的地址
};

typedef struct node Node;
typedef Node * Link;

/* ===================
 功能:初始化頭指針
 返回:void
=================== */
void init_head_node(Link *head)
{
    *head = NULL;    //頭指針置空
}

/* =========================
 功能:從鏈表頭部插入結點
 返回:void
========================= */
void insert_head_node(Link newnode, Link *head)
{
    newnode->next = *head;
    *head = newnode;
}

/* =================
 功能:打印鏈表
 返回:void
================= */
void display_link(Link head)
{
    Link temp = head;
    while (temp != NULL)    //遍歷鏈表
    {
        printf("%d\n", temp->num);
        temp = temp->next;
    }
}

int main()
{
    Link head;              //創建頭指針
    Link newnode;           //創建新結點

    init_head_node(&head);  //初始化頭指針

    for (int i = 0; i < 10; i++)
    {
        newnode = (Link)malloc(sizeof(Node));  //逐一爲結點分配空間
        newnode->num = i + 1;                  //逐一爲結點數據域賦值
        insert_head_node(newnode,&head);       //頭插
    }

    printf("頭插後的鏈表爲:\n");
    display_link(head);                        //打印鏈表
    
    return 0;
}

運行結果:

頭插後的鏈表爲:
10
9
8
7
6
5
4
3
2
1

3.2 尾插

從鏈表的尾部插入新的節點。

#include <stdio.h>
#include <stdlib.h>

/* =================
 定義鏈表數據結構
================= */
struct node
{
    int num;
    struct node *next;    //next存放下一個結點的地址
};

typedef struct node Node;
typedef Node * Link;

/* ===================
 功能:初始化頭指針
 返回:void
=================== */
void init_head_node(Link *head)
{
    *head = NULL;    //頭指針置空
}

/* =========================
 功能:從鏈表尾部插入結點
 返回:void
========================= */
void insert_tail_node(Link newnode, Link *head)
{
    if (NULL == *head)    //判斷是否爲空表
    {
        newnode->next = NULL;
        *head = newnode;
    }
    else
    {
        Link temp = *head;
        while (temp->next != NULL)  //找到最後一個結點
        {
            temp = temp->next;
        }

        temp->next = newnode;       //插入結點
        newnode->next = NULL;
    }
}

/* =================
 功能:打印鏈表
 返回:void
================= */
void display_link(Link head)
{
    Link temp = head;
    while (temp != NULL)    //遍歷鏈表
    {
        printf("%d\n", temp->num);
        temp = temp->next;
    }
}

int main()
{
    Link head;       //創建頭指針
    Link newnode;    //創建新結點

    init_head_node(&head);  //初始化頭指針

    for (int i = 0; i < 10; i++)
    {
        newnode = (Link)malloc(sizeof(Node));  //逐一爲結點分配空間
        newnode->num = i + 1;                  //逐一爲結點數據域賦值
        insert_tail_node(newnode,&head);       //尾插
    }

    printf("尾插後的鏈表爲:\n");
    display_link(head);                        //打印鏈表
    
    return 0;
}

運行結果:

尾插後的鏈表爲:
1
2
3
4
5
6
7
8
9
10

3.3 中間插入

從鏈表的中間插入新的節點。

#include <stdio.h>
#include <stdlib.h>

/* =================
 定義鏈表數據結構
================= */
struct node
{
    int num;
    struct node *next;    //next存放下一個結點的地址
};

typedef struct node Node;
typedef Node * Link;

/* ===================
 功能:初始化頭指針
 返回:void
=================== */
void init_head_node(Link *head)
{
    *head = NULL;    //頭指針置空
}

/* =========================
 功能:從鏈表尾部插入結點
 返回:void
========================= */
void insert_tail_node(Link newnode, Link *head)
{
    if (NULL == *head)    //判斷是否爲空表
    {
        newnode->next = NULL;
        *head = newnode;
    }
    else
    {
        Link temp = *head;
        while (temp->next != NULL)  //找到最後一個結點
        {
            temp = temp->next;
        }

        temp->next = newnode;       //插入結點
        newnode->next = NULL;
    }
}

/* =====================
 功能:從中間插入結點
 返回:是否成功執行
===================== */
int insert_mid_node(Link newnode, Link head, int num)
{
    if (NULL == head)      //判斷是否爲空表,空表則退出
    {
        return -1;
    }

    Link temp = head;
    while (temp != NULL)       //遍歷鏈表
    {
        if (num == temp->num)  //判斷是否爲要插入的目標結點,是則插入 
        {
            newnode->next = temp->next;
            temp->next = newnode;
            return 0;
        }

        temp = temp->next;
    }

    return -1;    //遍歷整個鏈表也找不到目標結點,退出
}

/* =================
 功能:打印鏈表
 返回:void
================= */
void display_link(Link head)
{
    Link temp = head;
    while (temp != NULL)    //遍歷鏈表
    {
        printf("%d\n", temp->num);
        temp = temp->next;
    }
}

int main()
{
    Link head;       //創建頭指針
    Link newnode;    //創建新結點

    init_head_node(&head);  //初始化頭指針

    for (int i = 0; i < 10; i++)
    {
        newnode = (Link)malloc(sizeof(Node));  //逐一爲結點分配空間
        newnode->num = i + 1;                  //逐一爲結點數據域賦值
        insert_tail_node(newnode,&head);       //尾插
    }

    newnode = (Link)malloc(sizeof(Node));      //爲新結點分配空間
    newnode->num = 11;
    insert_mid_node(newnode,head,5);           //在數據域爲5的結點後插入結點

    printf("從中間插入後的鏈表爲:\n");
    display_link(head);                        //打印鏈表
    
    return 0;
}

運行結果:

從中間插入後的鏈表爲:
1
2
3
4
5
11
6
7
8
9
10

4. 遍歷鏈表

/* =================
 功能:打印鏈表
 返回:void
================= */
void display_link(Link head)
{
    Link temp = head;
    while (temp != NULL)    //遍歷鏈表
    {
        printf("%d\n", temp->num);
        temp = temp->next;
    }
}

找最後一個結點:temp->next != NULL;
找所有結點:temp != NULL;

5. 刪除結點

#include <stdio.h>
#include <stdlib.h>

/* =================
 定義鏈表數據結構
================= */
struct node
{
    int num;
    struct node *next;    //next存放下一個結點的地址
};

typedef struct node Node;
typedef Node * Link;

/* ===================
 功能:初始化頭指針
 返回:void
=================== */
void init_head_node(Link *head)
{
    *head = NULL;    //頭指針置空
}

/* =========================
 功能:從鏈表尾部插入結點
 返回:void
========================= */
void insert_tail_node(Link newnode, Link *head)
{
    if (NULL == *head)    //判斷是否爲空表
    {
        newnode->next = NULL;
        *head = newnode;
    }
    else
    {
        Link temp = *head;
        while (temp->next != NULL)  //找到最後一個結點
        {
            temp = temp->next;
        }

        temp->next = newnode;       //插入結點
        newnode->next = NULL;
    }
}

/* ===================
 功能:刪除某個結點
 返回:是否成功
=================== */
int del_mid_node(Link *head, int num)
{
    if (NULL == *head)    //判斷是否爲空表,空表則退出
    {
        return -1;
    }

    Link temp = *head;
    if (num == (*head)->num)    //判斷頭結點是否是要刪除的結點,是則刪除
    {
        *head = (*head)->next;  //刪除結點
        free(temp);             //釋放
        temp = NULL;            //置空

        return 0;
    }

    Link ptr = temp;            //ptr指向temp的結點
    temp = temp->next;          //temp指向下一個結點,即ptr指向temp前面的結點

    while (temp != NULL)        //遍歷鏈表
    {
        if (num == temp->num)   //判斷是否是要刪除的結點,是則刪除
        {
            ptr->next = temp->next;
            free(temp);
            temp = NULL;

            return 0;
        }

        ptr = temp;
        temp = temp->next;
    }

    return -1;    //遍歷整個鏈表也找不到目標結點,則退出
}

/* =================
 功能:打印鏈表
 返回:void
================= */
void display_link(Link head)
{
    Link temp = head;
    while (temp != NULL)    //遍歷鏈表
    {
        printf("%d\n", temp->num);
        temp = temp->next;
    }
}

int main()
{
    Link head;       //創建頭指針
    Link newnode;    //創建新結點

    init_head_node(&head);  //初始化頭指針

    for (int i = 0; i < 10; i++)
    {
        newnode = (Link)malloc(sizeof(Node));  //逐一爲結點分配空間
        newnode->num = i + 1;                  //逐一爲結點數據域賦值
        insert_tail_node(newnode,&head);       //尾插
    }
    
    del_mid_node(&head,5);                     //刪除數據域爲5的結點

    printf("刪除數據域爲5的結點後的鏈表爲:\n");
    display_link(head);                        //打印鏈表
    
    return 0;
}

運行結果:

刪除數據域爲5的結點後的鏈表爲:
1
2
3
4
6
7
8
9
10

6. 鏈表逆序

#include <stdio.h>
#include <stdlib.h>

/* =================
 定義鏈表數據結構
================= */
struct node
{
    int num;
    struct node *next;    //next存放下一個結點的地址
};

typedef struct node Node;
typedef Node * Link;

/* ===================
 功能:初始化頭指針
 返回:void
=================== */
void init_head_node(Link *head)
{
    *head = NULL;    //頭指針置空
}

/* =========================
 功能:從鏈表尾部插入結點
 返回:void
========================= */
void insert_tail_node(Link newnode, Link *head)
{
    if (NULL == *head)    //判斷是否爲空表
    {
        newnode->next = NULL;
        *head = newnode;
    }
    else
    {
        Link temp = *head;
        while (temp->next != NULL)  //找到最後一個結點
        {
            temp = temp->next;
        }

        temp->next = newnode;       //插入結點
        newnode->next = NULL;
    }
}

/* ===============
 功能:逆序鏈表
 返回:是否成功
=============== */
int reverse_link(Link *head)
{
    /*判斷是否爲空表或只有一個結點,是則退出*/
    if (NULL == *head || NULL == (*head)->next)
    {
        return -1;
    }

    Link str = *head;
    Link ptr = str->next;
    Link temp = ptr->next;

    while (NULL != temp)
    {
        ptr->next = str;

        str = ptr;
        ptr = temp;
        temp = temp->next;
    }

    ptr->next = str;
    (*head)->next = NULL;
    *head = ptr;

    return 0;
}

/* =================
 功能:打印鏈表
 返回:void
================= */
void display_link(Link head)
{
    Link temp = head;
    while (temp != NULL)    //遍歷鏈表
    {
        printf("%d\n", temp->num);
        temp = temp->next;
    }
}

int main()
{
    Link head;       //創建頭指針
    Link newnode;    //創建新結點

    init_head_node(&head);  //初始化頭指針

    for (int i = 0; i < 10; i++)
    {
        newnode = (Link)malloc(sizeof(Node));  //逐一爲結點分配空間
        newnode->num = i + 1;                  //逐一爲結點數據域賦值
        insert_tail_node(newnode,&head);       //尾插
    }

    reverse_link(&head);

    printf("逆序後的鏈表爲:\n");
    display_link(head);                        //打印鏈表
    
    return 0;
}

運行結果:

逆序後的鏈表爲:
10
9
8
7
6
5
4
3
2
1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章