数据结构之链表篇 单链表 循环链表 双向链表

1.链表

链表是线性表的一种,由一系列节点(结点)组成,每个节点包含一个数据域和一个指向下一个节点的指针域。链表结构可以克服数组需要预先知道数据大小的缺点,而且插入和删除元素很方便,但是失去数组随机读取的优点。链表有很多种不同类型:单向链表,双向链表和循环链表。

在链表中第一个节点叫头节点(如果有头节点)头节点不存放有效信息,是为了方便链表的删除和插入操作,第一个有效节点叫首节点,最后一个节点叫尾节点。

2.单链表的操作

链表的操作一般有创建链表,插入节点,删除节点,遍历链表。插入节点的方法有头插法和尾插法,头插法是在头部插入,尾插法是在尾部插入。

下面以一个带头节点,采用尾插法的链表说明链表的各种操作。

#include<stdio.h>
#include<stdlib.h>
//单链表


//节点结构体
typedef struct node
{
    int value;//数据域
    struct node*next;//指针域
}Node;

Node*createList();//创建链表并且返回头节点指针
void deleteNode(Node*head);//删除节点
void insertNode(Node*head);//插入节点
void travelList(Node*head);//遍历链表

int main()
{
    Node*head=createList();
    travelList(head);
    insertNode(head);
    travelList(head);
    deleteNode(head);
    travelList(head);
    return 0;
}
//创建链表,返回头节点指针
Node*createList()
{
    //采用尾插法
    Node*head;//头节点
    Node*tail;//尾节点
    Node*temp=NULL;
    int i,value,size;
    head=(Node*)malloc(sizeof(Node));//头节点
    head->value=0;
    head->next=NULL;
    tail=head;
    printf("输入节点个数: ");
    scanf("%d",&size);
    printf("输入各个节点的值: ");

    for(i=0;i<size;i++)
    {
        scanf("%d",&value);
        temp=(Node*)malloc(sizeof(Node));
        temp->value=value;
        tail->next=temp;//让尾节点的指针域指向新创建的节点
        tail=temp;//尾节点改为新创建的节点
        tail->next=NULL;//让尾节点的指针域为空
    }
    return head;
}
//遍历链表
void travelList(Node*head)
{
    while(head->next!=NULL)
    {
        printf("%d\n",head->next->value);
        head=head->next;
    }
}
//插入节点
void insertNode(Node*head)
{
    int value;
    int position;
    int pos=0;
    Node*pre=NULL;//用来保存要插入节点的前一个节点
    Node*newNode;
    printf("输入要插入节点的值: ");
    scanf("%d",&value);
    printf("要插入的位置: ");
    scanf("%d",&position);
    while(head!=NULL)
    {
        pos++;
        pre=head;
        head=head->next;
        if(pos==position)
        {
            newNode=(Node*)malloc(sizeof(Node));
            newNode->value=value;
            newNode->next=pre->next;
            pre->next=newNode;
        }
    }
}
//删除节点
void deleteNode(Node*head)
{
    int value;
    Node*pre=head;
    Node*current=head->next;
    printf("输入要删除节点的值: ");
    scanf("%d",&value);
    while(current!=NULL)
    {
        if(current->value==value)
        {
            pre->next=current->next;
            free(current);//释放空间
            break;
        }
        pre=current;
        current=current->next;
    }
}

3.循环链表

循环链表就是让尾节点的指针域不再是NULL,而是指向头节点从而形成一个环。循环链表与单链表的操作没有多少差别,只是判断链表是否空应该是

**  tail->next==head。**

4.双向链表

双向链表的每一个节点都有两个指针域,一个前驱指针,指向前一个节点,头节点的前驱指针为NULL,一个后继指针,指向后一个节点,尾节点的后继指针为NULL。双向链表可以从任一个节点开始访问到前后节点,不像单链表只能向前。代码如下。

#include<stdio.h>
#include<stdlib.h>
//双向链表
typedef struct node
{
    int value;//数据域
    struct node* lNext;//前驱指针
    struct node* rNext;//后继指针
}Node;

Node*createList();//创建链表并且返回头节点指针
void deleteNode(Node*head);//删除节点
void insertNode(Node*head);//插入节点
void travelList(Node*head);//遍历链表

int main()
{

    Node*head=createList();
    travelList(head);
    insertNode(head);
    travelList(head);
    deleteNode(head);
    travelList(head);
    return 0;
}

Node*createList()
{
    Node*head,*tail,*temp;
    int num,value,i;
    head=(Node*)malloc(sizeof(Node));//头节点
    head->value=0;
    head->lNext=NULL;
    head->rNext=NULL;
    tail=head;
    printf("输入节点个数: ");
    scanf("%d",&num);
    printf("输入各个节点的值: ");
    for(i=0;i<num;i++)
    {
        scanf("%d",&value);
        temp=(Node*)malloc(sizeof(Node));
        temp->value=value;
        temp->lNext=tail;
        tail->rNext=temp;
        tail=temp;
        tail->rNext=NULL;
    }
    return head;
}


void deleteNode(Node*head)//删除节点
{

    int value;
    Node*pre;
    Node*current=head->rNext;
    printf("输入要删除节点的值: ");
    scanf("%d",&value);
    pre=head;
    while(current!=NULL)
    {
        if(current->value==value)
        {
            pre->rNext=current->rNext;//上一个节点指向下一个节点
            current->rNext->lNext=pre;//下一个节点的前驱指针指向上一个节点
            free(current);//删除该节点
        }
        pre=current;
        current=current->rNext;
    }
}

void insertNode(Node*head)//插入节点
{
    Node*pre,*temp;
    int value,pos;
    int num=0;
    printf("输入要插入的值: ");
    scanf("%d",&value);
    printf("输入要插入的位置: ");
    scanf("%d",&pos);
    while(head!=NULL)
    {
        num++;
        pre=head;//保存上一个节点
        head=head->rNext;//当前节点
        if(pos==num)
        {
            temp=(Node*)malloc(sizeof(Node));
            temp->value=value;
            temp->lNext=pre;
            temp->rNext=head;
            head->lNext=temp;
            pre->rNext=temp;
        }
    }
}

void travelList(Node*head)//遍历链表
{
    while(head->rNext!=NULL)
    {
        printf("%d\n",head->rNext->value);
        head=head->rNext;
    }
}
相关推荐
欧阳枫落12 分钟前
python 2小时学会八股文-数据结构
开发语言·数据结构·python
手握风云-25 分钟前
零基础Java第十六期:抽象类接口(二)
数据结构·算法
<但凡.1 小时前
编程之路,从0开始:知识补充篇
c语言·数据结构·算法
f狐0狸x2 小时前
【数据结构副本篇】顺序表 链表OJ
c语言·数据结构·算法·链表
Light602 小时前
低代码牵手 AI 接口:开启智能化开发新征程
人工智能·python·深度学习·低代码·链表·线性回归
Tmbcan2 小时前
zkw 线段树-原理及其扩展
数据结构·zkw 线段树
2301_801760932 小时前
数据结构--PriorityQueue
数据结构
乐悠小码2 小时前
数据结构------队列(Java语言描述)
java·开发语言·数据结构·链表·队列
爱吃生蚝的于勒7 小时前
C语言内存函数
c语言·开发语言·数据结构·c++·学习·算法
ChoSeitaku12 小时前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表