单链表的基本操作

来源:互联网 发布:淘宝怎样收藏店铺 编辑:程序博客网 时间:2024/06/07 02:34

链表:链表是由一系列可以在运行时动态生成的节点组成,是一种非连续,非顺序的线性表。节点包括两部分内容:一个是本节点的数据域,另一个是下一个节点的指针域,最后一个数据元素指向NULL。

这里写图片描述

接下来看一下链表的基本操作:

#include <stdio.h> //头文件的引用#include <stdlib.h>#include <assert.h>#include <string.h>typedef int DataType; //typedef定义int的别名typedef struct ListNode //typedef定义结构体{    DataType data;    struct ListNode* next;}ListNode; 

1.建立一个新的节点
用malloc函数动态开辟一块空间,并对这个空间初始化,指向NULL.

ListNode *NewListNode(DataType x){    ListNode *node = (ListNode*)malloc(sizeof(ListNode));    node->data = x;    node->next = NULL;    return node;}

2.打印链表
新建一个指针指向头节点,利用while循环进行链表的遍历。

void PrintList(ListNode* pList){    ListNode *cur = pList;    while (cur)    {        printf("%d ", cur->data);        cur = cur->next;    }    printf("\n");

3.在链表的尾部插入一个节点
这个操作需要考虑链表的节点是否为空。
当节点为空时,创建一个新节点,作为ppList;
当节点不为空时,让指向NULL节点的节点指向新建节点,新建节点指向NULL.

这里写图片描述

void PushBack(ListNode** ppList, DataType x){    if (*ppList == NULL)//当单链表为空的时候    {        *ppList = NewListNode(x);    }    else    {        ListNode *tail = *ppList;        while (tail->next != NULL)        {            tail = tail->next;        }        tail->next = NewListNode(x);    }}

测试代码:

    ListNode *List = NULL;    PushBack(&List, 1);    PushBack(&List, 2);    PushBack(&List, 3);    PushBack(&List, 4);    PushBack(&List, 5);    PrintList(List);

4.删除链表的尾节点
此操作需要考虑三种情况:
当链表为空时,直接返回return;
当链表有一个节点时,直接用free函数释放节点;
当链表有多个节点时,定义两个指针,一个指针先开始遍历链表另一个指针紧随其后,当第一个指针遍历到最后一个时停止,后面这个指针在倒数第二个节点,让倒数第二个节点指向NULL,释放最后一个节点。

这里写图片描述

void PopBack(ListNode** ppList){    ListNode *cur = *ppList;    if (*ppList == NULL)//单链表为空    {        return;    }    else if (cur->next == NULL)//单链表有一个节点    {        free(*ppList);        *ppList = NULL;    }    else //单链表有多个节点    {        ListNode *prev = NULL;        while (cur->next != NULL)        {            prev = cur;            cur = cur->next;        }        prev->next = NULL;        free(cur);    }}

测试代码:

    ListNode *List = NULL;    PushBack(&List, 1);    PushBack(&List, 2);    PushBack(&List, 3);    PushBack(&List, 4);    PushBack(&List, 5);    PrintList(List);    PopBack(&List);    PrintList(List);

5.在链表的头部插入一个节点
当链表为空时,直接新建一个节点作为链表的头节点;
当链表不为空时,让新建节点指向原来的头节点,新建节点为头插后的头节点。

这里写图片描述

void PushFront(ListNode** ppList, DataType x){    if (*ppList == NULL)    {        *ppList = NewListNode(x);    }    else    {        ListNode *prev = NewListNode(x);        prev->next = *ppList;        *ppList = prev; //将新建节点作为链表的头节点    }}

测试代码:

    ListNode *List = NULL;    PushBack(&List, 1);    PushBack(&List, 2);    PushBack(&List, 3);    PushBack(&List, 4);    PushBack(&List, 5);    PrintList(List);    PushFront(&List, 43);    PrintList(List);

6.删除链表的头节点
当链表为空的时候,return返回;
当链表只有一个节点的时候,直接free,并置为NULL;
当链表有多个节点时,先将第二个节点保存然后free第一个节点,将头节点指向第二个节点。

这里写图片描述

void PopFront(ListNode** ppList){    ListNode *cur = *ppList;    if (*ppList == NULL)    {        return;    }    else if (cur->next == NULL)    {        free(cur);        *ppList= NULL;    }    else    {        *ppList = cur->next;        free(cur);    }

测试代码:

    ListNode *List = NULL;    PushBack(&List, 1);    PushBack(&List, 2);    PushBack(&List, 3);    PushBack(&List, 4);    PushBack(&List, 5);    PrintList(List);    PopFront(&List);    PrintList(List);

7.查找结点
定义一个指针对链表进行遍历,判断节点的值是否是需要的那个,如果等于就返回这个节点,不等于返回空。

ListNode* Find(ListNode* pList, DataType x){    ListNode *cur = pList;    while (cur)    {        if (cur->data == x)        {            return cur;        }        cur = cur->next;    }    return NULL;}

测试代码:

    ListNode *List = NULL;    PushBack(&List, 1);    PushBack(&List, 2);    PushBack(&List, 3);    PushBack(&List, 4);    PushBack(&List, 5);    PrintList(List);ListNode* tmp=Find(List, 3);if (tmp){   tmp->data = 300;//对找到的数值可进行修改}

8.在链表指定位置的前面插入一个节点
在这里无需考虑无节点的情况
当有一个节点时,这里的问题就转化为头插;
当有多个节点的时候,定义一个指向头节点的指针遍历到链表指定节点的前一个位置,接着创建新的节点,改变指向关系。
这里写图片描述

void Insert(ListNode** ppList, ListNode* pos, DataType x){    assert(pos);    if ( pos==*ppList)    {        PushFront(ppList,x);    }    else    {        ListNode *cur = *ppList;        while (cur->next != pos)        {            cur = cur->next;        }        ListNode *prev = NewListNode(x);        cur->next = prev;        prev->next = pos;    }}

测试代码:

    ListNode *List = NULL;    PushBack(&List, 1);    PushBack(&List, 2);    PushBack(&List, 3);    PushBack(&List, 4);    PushBack(&List, 5);    PrintList(List);    ListNode *pos = List;    pos = pos->next;    Insert(&List, pos, 46);//特别注意这传参时,传pos如果传数值的话,类型有差异    PrintList(List);

9.删除指定的链表节点
此操作也无需考虑链表为空
当指定位为空的时候,进行头删;
当指定位的next为空的时候,进行尾删;
当指定位pos在中间时,就要进行指针指向的改变;
这里写图片描述

void Erase(ListNode** ppList, ListNode* pos){    assert(pos);    if (pos == NULL)    {        PopFront(ppList);    }    else if (pos->next == NULL)    {        PopBack(ppList);    }    else    {        ListNode *cur = *ppList;        ListNode *prev = pos->next;        while (cur->next != pos)        {            cur = cur->next;        }        cur->next = prev;        free(pos);        pos = NULL;    }   }

测试代码:

    ListNode *List = NULL;    PushBack(&List, 1);    PushBack(&List, 2);    PushBack(&List, 3);    PushBack(&List, 4);    PushBack(&List, 5);    PrintList(List);    ListNode *pos = List;    pos = pos->next;    Erase(&List, pos);    PrintList(List);
原创粉丝点击