【数据结构】——单链表详细介绍

上篇文章介绍了顺序表的一些操作,不知道各位有没有发现了顺序表的一些缺点,比如

  • 插入删除操作所需要移动的元素很多,浪费算力。
  • 必须为数组开足够的空间,否则有溢出风险。

引入另一种线性结构引入链表可以解决顺序表的这一些缺点。

链表是一种常见的数据结构,它由一系列的节点构成,每个节点包含一个值和一个指向下一个节点的指针。链表的基本结构如下图所示:

data1|next
data2|next
data3|next
NULL

每个节点之间在物理上并不是连续的,逻辑上连续。
链表主要有单链表,双链表,循环链表

data1|next
data2|next
data3|next
NULL
data1|next
data2|next
data3|next
other
other
data1|next
data2|next
data3|next

本文介绍单链表的有关操作

//定义结点类型
typedef struct Node {
    int data;      				//单链表数据域
    struct Node *next;          //单链表的指针域
} Node;  

要实现的功能

Node*Init();
//创建一个结点
Node* CreateNode(DateType x);
//打印or遍历 单链表
void Print(Node* head);
//销毁单链表
void Destory(Node* head);
//单链表头插创建链表
Node*HeadInsert();
//单链表尾插创建链表
Node*TailInsert();
//获得链表长度
int GetLenth(Node*head);
//单链表结点查找,按值
Node* Find_date(Node* head, DateType x);
//单链表结点查找,按位
Node* Find_pos(Node* head, int pos);
//单链表插入,成为第i个节点
void Insert(Node*head,int pos,DateType x);
//单链表结点删除(删除pos位置的结点)
void Erase(Node*head, int pos);


初始化链表

初始化主要完成以下工作:创建一个单链表的头节点
有了头节点后逐步向头节点后面添加节点就可以了

Node* Init()
{
    Node* Head;
    Head = (Node*)malloc(sizeof(Node));      
    if (Head == NULL) {                    
        perror("malloc:");
        return;                 
    }
    Head->next = NULL;       
    return Head;
}

创建一个节点

Node* CreateNode(DateType x)
{
    Node* newNode = malloc(sizeof(Node));
    newNode->Date = x;
    newNode->next = NULL;
    return newNode;
}

遍历单链表

声明一个指针curNode,从头结点指向的第一个结点开始,如果curNode不为空,那么就输出当前结点的值,并将curNode指向下一个结点,直到遍历到最后一个结点为止。

void Print(Node* head)
{
    Node* curNode = head->next;
    while (curNode)
    {
        printf("%4d", curNode->data);
        curNode = curNode->next;
    }
    printf("\n");
}

销毁单链表

可不能直接free(head),因为链表在物理结构上是不连续存储的,把表头销毁之后就找不到其他节点了,所以必须要把表头留着,销毁链表必须要一个结点一个结点去销毁(表头要移动)!!最后不要忘记把head置为NULL。

void Destory(Node* head)
{
    Node* curNode = head;
    while (curNode)
    {
        head = curNode->next;
        free(curNode);
        curNode = head;
    }
    head = NULL;
}

头插法创建单链表

head->next = insertNode
insertNode->next = head->next
head->next = insertNode
insertNode->next = head->next
head|next
data1|^
NULL
head|next
data2|next
data1|^
Node*HeadInsert()
{
 	Node* head = Init();
    DateType x;
    while (scanf("%d", &x) != EOF)
    {
        Node* insertNode = CreateNode(x);
        insertNode->next = head->next;
        head->next = insertNode;
    }
	return head;
}

测试结果
在这里插入图片描述
EOF通过ctrl+z实现,可能要多输入几次

尾插法创建单链表

pNode->next = insertNode
>pNode= insertNode
pNode->next = insertNode
pNode= insertNode
head|next
data1|^
NULL
head|next
data1|next
data2|^
Node*TailInsert()
{
	Node* head=Init();            
    Node* pNode = head;                 //pNode始终指向终端结点,开始时指向头结点
    int x;                        
    while (scanf("%d", &x) != EOF) 
    {
        Node* insertNode = CreateNode(x);
        pNode->next = insertNode;
        pNode= insertNode;
    }
    pNode->next = NULL;
    return head;
}

测试结果
在这里插入图片描述

求单链表长度

求链表长度不算表头

//求单链表的长度
int GetLength(Node*head){
    Node *p = head->next;
    int len = 0;
    while(p){
        len++;
        p = p->next;
    }
    return len;
}

查找

按值查找
Node* Find_date(Node* head, DateType x)
{
    Node* p = head->next;
    while (p && p->data != x) {
        p = p->next;
    }
    return p;
}
按位查找

头结点算0

Node* Find_pos(Node* head, int pos)
{
    int i = 1;
    Node* p = head->next;
    if (pos == 0)
        return head;
    if (pos < 1)
        return NULL;
    while (p && i < pos) {
        p = p->next;
        i++;
    }
    return p; //如果pos大于表长,p=NULL,直接返回p即可
}

插入

这里所说的插入是将值为x的新结点插入到单链表的第pos个位置上(pos是从0开始计数的)。(不包括头结点)

从表头开始遍历,查找第 i-1个结点,即插入位置的前驱结点p,然后令新结点s的指针域指向p的后继结点,再令结点p的指针域指向新结点s。

void Insert(Node* head, int pos, DateType x)
{
    Node* p = Find_pos(head, pos - 1);
    Node* s = CreateNode(x);
    s->next = p->next;
    p->next = s;
}

测试结果
在这里插入图片描述

删除

X
X
p->next = Find_pos(head,pos + 1)
Find_pos(head,pos - 1)
pos
Find_pos(head,pos +1)
void Erase(Node* head, int pos)
{
    Node* p = Find_pos(head,pos - 1);
    Node* eNode = p->next;
    p->next = Find_pos(head,pos + 1);
    free(eNode);
}

测试结果
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值