头指针单向链表基本操作


title: 头指针单向链表基本操作
date: 2020-10-04 16:47:34
tags: 单链表基本操作
categories: 数据结构


感觉每次自己提前写的东西都和老师讲的书上内容不太一样= =
当然大多数是老师讲的更正规一些,毕竟我只是一个会了链表本质就瞎玩的人
属于自己琢磨,自己造的那种,很多东西也是不怎么规范
但是有的东西我就觉得自己的更好
比如下面所说…

课本上写的是以头指针为基本单位,每次开一个头指针,即可视为开辟了一个链表。

而我参考了动态数组静态数组的写法,将头指针作为了结构体中的一个成员变量,另一个成员变量存储这个链表的长度。每次开一个结构体变量,视为开辟了一个链表。

谈一下我的做法的优越性:

在插入删除的时候,我可以在一开始就判断要插入或删除的结点序号是否存在,因为我有链表的长度,如果结点序号非法,那么直接终止就可以了。然而书上的做法,它只有一个头指针(头结点),因此在插入删除的时候需要先去遍历,至于结点序号存不存在则需要在遍历完之后才能知道。

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

// 在链表尾添加的结点中数据域的内容data
#define TAIL_ADD_NODE_DATA_NUMBER 6
// 要删除的结点的序列号
#define DELETED_NODE_SERIAL 1
// 要删除的结点中存的数据
#define DELETED_NODE_DATA 1
// 初始化的链表长度
#define INITIAL_LENGTH 5
typedef struct list
{
    int data;
    struct list *next;
} Node, *List;

typedef struct pHead
{
    // 一个头指针可以确定一个链表
    List pHead;
    // 这里标上链表的长度可以省去很多麻烦
    int length;
} LinkList;

void Print();
void PrintList(LinkList);
void InitializeList(LinkList &);
// 在链表尾添加一个结点
void AddTail(LinkList &, int);
// 插入一个 数据域 data = n的结点, 并且使之成为链表中第i个结点
void InsertNode(LinkList *, int i, int n);
// 删除第 i 个结点
void DeleteNodeBySerialNumber(LinkList *, int i);
// 删除 data = n 的结点
void DeleteNodeByContainedData(LinkList &, int);
// 释放链表
void FreeList(LinkList &);

int main(void)
{
    // 每使用一次LinkList,就相当于开辟了一个链表
    LinkList list;
    // 初始化链表
    list.pHead = NULL;
    list.length = 0;
    InitializeList(list);
    PrintList(list);
    AddTail(list, TAIL_ADD_NODE_DATA_NUMBER);
    PrintList(list);
    DeleteNodeBySerialNumber(&list, DELETED_NODE_SERIAL);
    PrintList(list);
    DeleteNodeBySerialNumber(&list, 2);
    PrintList(list);
    InsertNode(&list, 1, 7);
    PrintList(list);
    InsertNode(&list, 3, 8);
    PrintList(list);
    InsertNode(&list, 7, 100);
    PrintList(list);
    DeleteNodeBySerialNumber(&list, 7);
    PrintList(list);
    FreeList(list);
    PrintList(list);
}

void Print()
{
    printf("******************************************\n");
}

void PrintList(LinkList list)
{
    List temp = list.pHead;
    printf("当前链表长度为 %d\n", list.length);
    if(list.length == 0)
        return;
    printf("打印链表内容\n");
    while (temp != NULL)
    {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("\n");
    Print();
}

void InitializeList(LinkList &list)
{
    printf("初始化链表...\n");
    List temp = NULL;
    for (int i = 0; i < INITIAL_LENGTH; i++)
    {

        List p = (List)malloc(sizeof(Node));
        p->next = NULL;
        p->data = i + 1;
        if (i == 0)
            list.pHead = p;
        else
            temp->next = p;
        temp = p;
    }
    list.length = INITIAL_LENGTH;
}

void AddTail(LinkList &list, int data)
{
    printf("向链表末尾添加 数据域data = %d的结点...\n", data);
    List p = (List)malloc(sizeof(Node));
    p->data = data;
    p->next = NULL;
    // 检查链表是否为空,如果是空链表,则需要改变头指针
    if (list.pHead == NULL)
        list.pHead->next = p;
    else
    {
        List temp = list.pHead;
        while (temp->next != NULL)
            temp = temp->next;
        temp->next = p;
    }
    list.length++;
}

void DeleteNodeBySerialNumber(LinkList *pList, int serial)
{

    if (!((serial >= 1) && (serial <= pList->length)))
        exit(EXIT_FAILURE);
    printf("删除第%d个结点...", serial);
    List deletedNode = NULL;

    // 如果只删除第一个,要删除的结点是没有上一个结点的,其实找上一个
    // 结点的意义也就无非是要找到这个结点的地址,然后改变上一个结点中指针域
    // 的指向,让上一个结点指向被删除的结点指向的结点。
    // 综上所述,删除结点就是要找到前指针。

    if (serial == 1)
    {
        deletedNode = pList->pHead;
        pList->pHead = pList->pHead->next;
    }
    else
    {
        List temp = pList->pHead;
        // 请细细思考for循环中为什么初始化i = 1
        // 并且用 i < serial - 1 作为判断条件
        // 其中有坑
        for (int i = 1; i < serial - 1; i++)
            temp = temp->next;
        deletedNode = temp->next;
        temp->next = temp->next->next;
    }
    free(deletedNode);
    pList->length--;
}

void InsertNode(LinkList *pList, int serial, int data)
{
    printf("在第%d号位插入一个数据域为data = %d的结点...\n", serial, data);
    if (!((serial >= 1) && (serial <= pList->length + 1)))
        exit(EXIT_FAILURE);
    List p = (List)malloc(sizeof(Node));
    p->data = data;
    p->next = NULL;
    if (serial == 1)
    {
        p->next = pList->pHead;
        pList->pHead = p;
    }
    else
    {
        List temp = pList->pHead;
        for (int i = 1; i < serial - 1; i++)
            temp = temp->next;
        p->next = temp->next;
        temp->next = p;
    }
    pList->length++;
}

void FreeList(LinkList &list)
{
    printf("释放链表在堆区开辟的所有空间...\n");
    while (list.pHead != NULL)
    {
        List deletedNode = list.pHead;
        list.pHead = (list.pHead)->next;
        free(deletedNode);
    }
    list.length = 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值