数据结构-链表

1.链表的概念

        链表(Linked List)是一种常见的数据结构,用于存储和组织数据。它由一系列节点(Node)组成,每个节点包含数据和指向下一个节点的指针。

        如图所示,是一个节点(Node)的组成,在数据域(Date)包含了数据,在指针域(Next)包含了指向下一个节点(Node)的指针。

        链表的特点是节点之间通过指针相互连接,形成一个链式结构。相比于数组,链表的大小可以动态地增加或减少,因为它不需要预先分配一块连续的内存空间。它的存储思想是用一组任意(即不连续 零散分布)的存储单元存放线性表的元素,链表可以根据需要灵活地插入、删除和修改节点。

2.单链表的实现

1.创建一个单链表节点
typedef struct node 
{
    DateType data;
    struct node *next;
}Node,*Link

p = (Link)malloc(sizeof(Node));

头指针:指向第一个节点的地址。

尾标志:终端节点的指针域为空。

这是一个空表 数据域和指针域都为空

如何将空表与非空表统一呢?

头节点:在单链表的第一个元素节点之前附设一个类型相同的节点,以便空表和非空表处理统一。

2.单链表的遍历操作
void displayNode(Link head)
{
    p = head->next;
    while(p!= NULL)
    {
        printf("%d ",p->date);
        p = p->next;
    }
}

p指针首先指向头节点的next,next存放了下一个节点的地址。p->data时,即读出了data1的数据,依此类推。

3.求单链表的元素个数
int length (Link head)
{
    p = head->next;
    count = 0;
    while(p! = NULL)
    {
        p = p->next;
        count++;
    }
    return count;
}

  与遍历操作一样,在遍历的时候加入count进行计数,然后返回。

4.单链表的查找操作
int queryNode(Link head,DataType x)
{
    p = head->next;
    while(p!=NULL)
    {
        if(p->data == x)
        {
            printf(data);
            return true;
        }
    }
    reture false;
}

移动指针p遍历链表,当读出的数据date等于x时,打印数据并返回true;

当遍历完所有数据都未能找到时,则返回false。

5.单链表的插入操作
bool insertNode(Link head, int i,DataType x)
{
    p = head;
    count = 0;//利用count来移动指针
    while(p!=NULL && count < i-1)//如果查询到空指针退出循环 当指针移动到所需要的位置也退出循环
    {
        p = p->next;
        count++;
    }
    if(p == NULL)
    {
        return false;
    }
    else
    {
        node = (Link)malloc(sizeof(Node));
        node->data = x;
        node->next = p->next;//node的指针域指向原本p的指向的节点
        p->next = node;//p的指针域指向node
        return true;
}
6.创建一个单链表

6.1头插法创建一个单链表

头插法:将待插入节点插在头节点后面(就是头节点的指针域存放节点新节点node的地址 新节点node存放head->next的地址 此时如果是一个数组,则数组存放在链表里的值则为反序的)

Link newList(DataType a[],int n)
{
    head = (Link)malloc(sizeof(Node));//创建一个头节点
    head->next = NULL;
    for(i=0;i<n;i++)
    {
        node = (Link)malloc(sizeof(Node));
        node->data = a[i];
        node->next = head->next;
        head->next = node;
    }
    return head;
}

程序流程如图所示

6.2 尾插法创建一个单链表

尾插法:将待插入节点插在终端节点的后面

初始化 创建一个头节点时

此时头节点和尾节点为同一个节点

Link newList(DataType a[],int n)
{
    head = (Link)malloc(sizeof(Node))
    head->next = NULL;
    rear = head;
    for(i=0;i<n;i++)
    {
        node = (Link)malloc(sizeof(Node));
        node->data = a[i];
        rear->next = node;
        rear = node;   
    }
    rear->next = NULL;
    return head;
}
7.单链表节点的删除

查找节点的过程中,如何保证指针p和q一前一后呢?

q = p;

p = p->next;

bool deleteNode(Link head,DataType x)
{
    if(head == NULL||head->next == NULL)//判断链表是否为空表
    {
        return false;
    }
    p = head->next;
    q = head;
    while(p!= NULL)
    {
        if(p->data == x)
        {
            q->next = p->next;
            free(p);
            return true;
        }
        else
        {
             q = p;
             p = p->next;   
        }
    }
    return false;
}

3.循环链表的实现

问:从单链表中某节点p出发如何找到其前驱?

        将单链表的首尾相接,将终端节点的指针域由空指针改为指向头节点,构成单循环链表,简称循环链表。

循环链表的特点

循环链表没有明显的尾端 如何避免死循环

与单链表不同 单链表的循环结束条件为p!=NULL 此时应该修改为p!=head

4.双向链表

双向链表:在单链表的每个节点中再设置一个指向其前驱节点的指针域。

用循环链表的方式找到p的前驱,在时间上需要更多的时间。

用双向链表的方式可以快速求得p的前驱,相应的需要占据更大的空间。

data:数据域 存储数据元素

prior:指针域 存储该节点的前驱节点的地址

next:指针域 存储该节点的后继节点地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值