链式表的理解

一.链表的概念:

定义:

链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现的一种线性存储结构。

特点:

链表由一系列节点(链表中每一个元素称为节点)组成,节点在运行时动态生成 (malloc),每个节点包括两个部分:

一个是存储数据元素的数据域

另一个是存储下一个节点地址的指针域

链表的构成:

链表通常是采用结构体的形式组织,例如:

typedef struct node {
         data_t data;//数据域,用来存放每个节点的数据
         struct node *next;//指针域,用来指向下一个节点
}link_t;

链表的操作

链表最大的作用是通过节点把离散的数据链接在一起,组成一个表,这大概就是链表 的字面解释了吧。 链表常规的操作就是节点的插入和删除,为了顺利的插入,通常一条链 表我们会人为地规定一个头节点。通常头节点还会有一个节点计数器,用于统计整条链表的节点个数。

链表与数组的对比

链表是通过节点把离散的数据链接成一个表,通过对节点的插入和删除操作从而实现 对数据的存取。而数组是通过开辟一段连续的内存来存储数据,这是数组和链表最大的区 别。数组的每个成员对应链表的节点,成员和节点的数据类型可以是标准的 C 类型或者是 用户自定义的结构体。数组有起始地址和结束地址,而链表是一个圈,没有头和尾之分, 但是为了方便节点的插入和删除操作会人为的规定一个根节点。


链表.h文件的封装

#ifndef _LINKLIST_H
#define _LINKLIST_H

typedef int data_t;//给int型变量起别名,防止如果要插入的数据不是int型
typedef struct node{
        data_t data;//数据域
        struct node *next;//指针域
}link_t;
//链表的创建
link_t *linklist_create();
//遍历链表
void linklistShow(link_t *head);
//按位置插入元素
int linklistInsertPos(link_t *head,int pos,data_t data);
//求链表的长度
int linklistGetLength(link_t *head);
//按位置删除节点
int linklistDeletePos(link_t *head,int pos);
//判空
int linklistIsEmpty(link_t *head);
//按位置查找
link_t *linklistSearchPos(link_t *head,int pos);
//按数据查找
link_t *linklistSearchData(link_t *head,data_t data);
//按数据删除
int linklistDeleteData(link_t *head,data_t data);
//按位置修改数据
int linklistUpdataPos(link_t *head,int pos,data_t newdata);
//按数据修改数据
int linklistUpdataData(link_t *head,data_t olddata,data_t newdata);
//清空链表
int linklistClear(link_t *head);
//销毁链表
int linklistDestory(link_t *head);
//倒置
int linklistInvert(link_t *head);
//排序
int linklistSort(link_t *head);

#endif

链表.c文件的封装

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#incldue <assert.h>
#include "linklist.h"

link_t *linklist_create()//链表头节点的创建
{
    link_t *head = (link_t *)malloc(sizeof(link_t));
    assert(NULL != head);
    head->data = -1;//头节点不存在有效元素
    head->next = NULL;
    return head;
}

void linklistShow(link_t *head)//遍历
{
    if(NULL == head)
        {
        return;
        }
    link_t *p = head->next;//新建一个指针指向头节点的下一个
    while(p != NULL)
    {
        printf("%d ",p->data);
        p = p->next;
    }
        puts(" ");
}

int linklistInsertPos(link_t *head,int pos,data_t data)
{
    //判断链表是否存在
    if(NULL == head)
    {
        return -1;
    }
    //判断位置是否合法
    int len = linklistGetLength(head);
    if(pos < 0 || pos > len)//插入位置小于或大于链表长度
        {
            return -1;
        }
    //创建新节点
    link_t *new = (link_t *)malloc(sizeof(link_t));
    new->data = data;
    //找到插入位置前一个节点
    link_t *p = head;
    for(int i = 0;i < pos;i++)
    {
        p = p->next;
    }
    new->next = p->next;
    p->next = new;
    
    return 0;
}

int linklistGetLength(link_t *head)//获得有效长度
{
    if(NULL == head)
    {
        return -1;
    }
    int len = 0;
    link_t *p = head;
    while(p->next != NULL)
    {
        len++;
        p = p->next;
    }
        return len;
}

int linklistDeletePos(link_t *head,int pos)
{
    //判表存在
    if(NULL == head)
    {
        return -1;
    }
    //判空
    if(linklistIsEmpty(head))
    {
        return -1;
    }
    //判断位置是否合法
    int len = linklistGetLength(head);
    if(pos < 0 || pos > len-1)
    {
        return -1;
    }
    //找到要删除位置的前一个位置
    link_t *p = head;
    for(int i = 0;i < pos;i++)
    {
            p = p->next;
    }
    //删除
    link_t *q = p->next;//q保存的是要删除的节点地址
    p->next = q->next;
    free(q);//删除后要释放q的空间
    q = NULL;
    return 0;
}

int linklistIsEmpty(link_t *head)//判空
{
    if(NULL == head)
    {
        return -1;
    }
    return head->next == NULL;
}

link_t *linklistSearchPos(link_t *head,int pos ,data_t data)//按位置查找
{
        if(NULL == head)
        {
            return NULL;
        }
        int len = linklistGetLength(head);
        if(pos < 0 || pos > len-1)
        {
            return NULL;
        }
        link_t *p = head->next;//查找的位置就是p的位置
        for(int i = 0;i < pos;i++)
        {
            p = p->next;
        }        
        return p;
}

link_t *linklistSearchData(link_t *head,data_t data)//按数据查找
{
        if(NULL == head)
        {
            return NULL;
        }
        link_t *p = head->next;
        while(p != NULL)
        {
            if(p->data == data)
            {
                    return p;
            }
            p = p->next;//如果不是该数据往下查找
        }
        reutrn NULL;
}

int linklistDeleteData(link_t *head,data_t data)//按数据删除
{
        if(NULL == head)
        {
            return -1;
        }
        link_t *p = head;
        while(p->next != NULL)
        {
            if(p->next->data == data)
            {
                link_t *q = p->next;//保存要删除的地址
                p->next = q->next;
                free(q);
                q = NULL;
                return 0;//删除完后正确返回
            }
           p = p->next;//如果没有找到该数据则遍历表
        }
        return -1;//如果没有说明没有该数据,错误返回
}

int linklistUpdataPos(link_t *head,int pos,data_t newdata)//按位置修改数据
{
        if(NULL == head)
        {
            return -1;
        }
        //查找这个数据
        link_t *p = linklistSearchPos(head,pos);
        if(NULL == p)
        {
            return -1;
        }
        p->data = newdata;
        return 0;    
}

int linklistUpdataData(link_t *head,data_t olddata,data_t newdata)
{
        if(NULL == head)
        {
            return -1;
        }
        link_t *p = linklistSearchData(head,olddata);
        if(NULL == p)
        {
            return -1;
        }
        p->data = newdata;
        return 0;
}

int linklistClear(link_t *head)
{
        if(NULL == head)
        {    
            return -1;
        }
            while(head->next != NULL)
            {
                linklistDeletePos(head,0);
            }
        
        return 0;
}

int linklistDestory(link_t **head)
{
        if(NULL == *head)//
        {
               return -1;
        }
        linklistClear(*head);//通过指向头节点的地址一个一个删头节点后的表
        free(*head);//最后删完释放这篇空间
        *head = NULL;
        return 0;
}

int linklistInvert(link_t *head)//倒置
{
        if(NULL == head)
        {
            return -1;
        }
        if(linklistIsEmpty(head))
        {
            return -1;
        }
        link_t *p =head->next;
        head->next = NULL;//将头节点和后面节点断开
        link_t *q;
        while(p != NULL)
        {
            q = p->next;
            p->next = head->next;
            head->next = p;
            p = q;
        }
        return 0;
}

int linklistSort(link_t *head)
{
    if(NULL == head)
    {
        return -1;
    }
    link_t *p = head->next;
    link_t *r = NULL,*q = NULL;
    head->next = NULL;//将链表断开
    while(p != NULL)
    {
        r = head;//r始终在头节点
        q = p->next;//保持待插入节点的下一个节点
        while(r->next != NULL && r->next->data)//r->next != NULL 当插入第一个节点的时候,r->next == NULL,不需要进入循环。直接插入在r的后面;
      //r->next->data > p->data 时候说明从大到小排列,要插入的元素应该从后面放,所有r需要循环偏移.直到r->next->data < p->data的时候就插入在r的后面;
        {
                r = r->next;
        }
            p->next = r->next;//将p插在r后面
            r->next = p;
           p = q;//将q保存的节点赋值给p,继续下一次循环
    }
        return 0;
}

链表倒置详解图

main.c函数实现

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

#include "linklist.h"
int main()
{
link_t *head = linklist_create();
if(NULL == head)
{
    return -1;
}
printf("create success..\n");
for(int i = 1; i < 11;i++)
linklistInsertPos(head,0,i*10);
linklistShow(head);

            return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值