关于数据结构(c语言)中,线性表中链式结构的大部分操作的代码实现

引入

        数据结构是计算机专业必学的一门课程,如果说算法是一个程序的操作动作,那么数据结构就是一个程序的灵魂,它让一段程序在运行的过程中,拥有足够强大的“内力”进行代码的实现。

        数据结构的三要素分为逻辑结构,存储结构和运算。而本篇文章将要介绍的线性表,是数据结构入门内容,也正因为是一个入门内容,它的重要性也不言而喻。将数据结构中的线性表学习透彻,将在数据结构之后的学习中打好坚实的基础。

        本篇文章将要介绍的,是线性表(逻辑结构)中的链式结构(存储结构),是线性表的基础之一,而在下列程序中,将要通过对链表的创建、判空、遍历输出、长度输出、升序排序(冒泡排序)、插入、删除的分段过程,对整体代码进行分析与解剖。

第一部分 头文件与结构体的创建

        创建一个结构体,使该结构体包含链表的数据域(用于存放一个结点的值)与指针域(用于存放一个结点指向下一结点的地址),利用typedef,使结构体便于在之后的操作部分便于声明,其中,NODE等价于struct Node,*PNODE等价于struct Node*。



#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<stdbool.h>

typedef struct Node
{
    int data; //数据域
    struct Node* pNext; //指针域
}NODE,*PNODE; //NODE等价于struct Node,PNODE等价于struct Node*

​

第二部分 函数声明

        提前对所需操作的函数进行函数声明,对链表进行创建、判空、遍历输出、长度输出、升序排序(冒泡排序)、插入、删除的操作,也便于为具体代码的书写理清思路。

PNODE create_list(void);
void traverse_list(PNODE pHead);
bool is_empty(PNODE pHead);
int length_list(PNODE pHead);
bool insert_list(PNODE pHead, int pos ,int val);
bool delete_list(PNODE pHead, int pos, int * pVal);
void sort_list(PNODE pHead);

第三部分 实例化与调用

        将结构体变量实例化为pHead,即此作为一个头指针,指向一个头结点(其中不含数据域),在之后的各项函数操作中,想要得到关于链表的所有信息时,只需得到其头结点即可知晓关于整个链表的信息。

int main(void)
{
    int val;
    PNODE pHead=NULL;
    pHead=create_list();
    printf("初始链表为:\n");
    traverse_list(pHead);
    if(is_empty(pHead))
    {
        printf("链表为空!\n");
    }
    else{
        printf("链表不空!\n");
    }
    insert_list(pHead,3,100);
    printf("插入元素后的链表为:\n");
    traverse_list(pHead);
    if(delete_list(pHead,3,&val))
    {
        printf("删除成功!删除的元素为:%d\n",val);
    }
    else
    {
        printf("删除失败!\n");
    }
    printf("删除元素后的链表为:\n");
    traverse_list(pHead);
    sort_list(pHead);
    printf("排序后的链表为:\n");
    traverse_list(pHead);
        int len=length_list(pHead);
    printf("链表的长度为:%d",len);
    return 0;
}

第四部分 各类操作的具体代码实现

1.链表的创建 PNODE create_list(void);

        a.定义len:用来存放有效结点的个数,i:循环指示符,val:用来临时存放用户输入的结点的值。

        b.使用malloc动态分配一个pHead作为整个链表的头结点,并判断其是否为空,对动态内存是否分配成功进行判断。定义一个尾指针指向头节点,将其设为空(防止整个链表仅有头结点时,尾指针成为野指针,造成数据溢出的风险)。

        c.输入链表的长度。

        d.进入以i为循环指示符的循环,为每一个结点的数据域分配输入的值。

        e.动态分配一个新结点,作为每一次循环依此挂在头结点之后的新结点,为新结点的数据域分配一个值。利用尾插法,使尾指针指向的下一个结点为新结点(即使头结点指向新结点),并使尾指针本身指向新结点,将新结点的指针域置为空(防止数据溢出)。 

        f.最后返回头指针。

        这样,就完成了一个链表的创建。

2.链表的遍历输出 void traverse_list(PNODE pHead);       

        创建一个新的临时指针,使该临时指针指向头结点的下一个结点,当临时指针指向的下一个结点不为空时,一直循环输出指向的结点的值,之后使该临时指针指向下一个结点,使代码具有健壮性。、

        这样,就完成了一个链表的遍历输出。         

3.链表的判空 bool is_empty(PNODE pHead);     

        若头结点指向的下一个结点(即首元结点:第一个有效结点)为空,则之后不可能再有结点,故整个链表为空,返回true,否则返回false。

4.链表的长度输出 int length_list(PNODE pHead);       

        定义一个循环次数指示符len,p为指向头结点下一个结点(首元结点)的临时指针,当p指向的结点不为空时,执行循环使p不断指向之后的结点,当为指到最后一个结点时,len都加一,以此得到链表的长度,最终返回该链表的长度len。

        这样,就完成了一个链表的长度输出。

5.链表的升序排序(冒泡排序) void sort_list(PNODE pHead)

        a.定义外层循环指示符i,内层循环指示符num,链表长度len,前一个指向结点的p,后一个指向结点的q,尾指针pTail。

        b.链表的冒泡排序的外层循环条件与数组完全一致,num的赋值也即为原数组冒泡排序内层循环的循环指示符循环条件,外层循环内部的准备工作:使p指向首元结点,使q指向首元结点的下一个结点,使尾指针暂时指向头结点。

        c.内层循环的条件即为原数组内层循环的条件变为num--,增大的代码的效率。内层循环内部,若前一个结点的数据域的值大于后一个结点的数据域的值,则使前一个结点绕开指向后一个结点,而使其指向后一个结点指向的下一个结点,使后一个结点反过来指向其前一个结点,使尾指针(即最开始指向头结点的指针)指向的下一个结点,从最开始指向的首元结点,改为指向“后一个结点”。最后,使尾指针往后移动一个位置,使其指向头结点之后的结点(可能是已经互换过的新结点),最后对p和q进行前一个结点和后一个结点的重置,继续循环操作。

        这样,就完成了对链表的升序排序。

6.链表的插入 bool insert_list(PNODE pHead, int pos, int val);

        形参列表中的pos代表插入新结点的位置,即插入现存结点的前面,val为插入新结点的数据域中的值。

        a. 通过效率很高的该循环条件:while(NULL!=p&&i<pos-1), 在插入的位置合法的条件下,对整个链表进行遍历。

        b.判断输入的pos是否合法,若不合法则返回false。

        c.创建一个新结点pNew,该结点即为要插入的结点,定义一个临时指针,使其指向将要插入新结点之前的结点,然后使新结点指向其下一个结点,最后使新结点之前的结点指向新结点,使整个链表重新连起来。

        这样,就完成了对链表中新结点的插入。

7.链表的删除 bool delete_list(PNODE pHead, int pos, int * pVal);

        形参列表中的pos代表删除结点的位置,pVal为存放删除结点数据域值的临时变量。

        a.大部分操作与链表的插入中的a、b步骤相同,不再赘述。

        b.定义一个临时指针q,使其指向待删除的结点。使pVal保存待删除结点的值。

        c.使待删除的结点的前一个结点指向待删除结点指向的后一个结点,将待删除结点覆盖。

        d.最后释放删除的结点,并将其置为空,防止数据溢出。

        这样,就完成了对链表结点的删除。

PNODE create_list(void)
{
    int len; //用来存放有效结点的个数
    int i;
    int val; //用来临时存放用户输入的结点的值
    PNODE pHead=(PNODE)malloc(sizeof(NODE)); //分配了一个不存放有效数据的头结点
    if(NULL==pHead)
    {
        printf("动态内存分配失败,程序终止!\n");
        exit(-1);
    }
    PNODE pTail=pHead;
    pTail->pNext=NULL;
    printf("请输入需要生成新结点的个数:len=");
    scanf("%d",&len);
    for(i=0;i<len;i++)
    {
        printf("请输入第%d个结点的值:",i+1);
        scanf("%d",&val);
        PNODE pNew=(PNODE)malloc(sizeof(NODE)); //分配一个新结点
        if(NULL==pNew)
    {
        printf("动态内存分配失败,程序终止!\n");
        exit(-1);
    }
    pNew->data=val;
    //尾插法,使新结点挂到头结点上
    pTail->pNext=pNew;
    pTail=pNew;
    pNew->pNext=NULL;
    }
    return pHead;
}

void traverse_list(PNODE pHead)
{
    PNODE p=pHead->pNext;
   while(NULL!=p)
   {
       printf("%d ",p->data);
       p=p->pNext;
   }
   printf("\n");
   return;
}

bool is_empty(PNODE pHead)
{
    if(NULL==pHead->pNext)
    {
        return true;
    }
    else
    {
        return false;
    }
}

int length_list(PNODE pHead)
{
    int len=0;
    PNODE p=pHead->pNext;
    while(NULL!=p)
    {
        p=p->pNext;
        len++;
    }
    return len;
}

void sort_list(PNODE pHead)
{
    int i;
    int j;
    int len=length_list(pHead);
    int num;
    PNODE p=pHead;
    PNODE q;
    PNODE pTail;
    for(i=0;i<len-1;i++)
    {
        num=len-i-1;
        p=pHead->pNext;
        q=p->pNext;
        pTail=pHead;
       while(num--)
        {
            if(p->data>q->data)
            {
              p->pNext=q->pNext;
              q->pNext=p;
              pTail->pNext=q;
            }
            pTail=pTail->pNext;
            p=pTail->pNext;
            q=p->pNext;
        }
    }
    return;
}

bool insert_list(PNODE pHead, int pos, int val)
{
    int i=0;
    PNODE p=pHead;
    while(NULL!=p&&i<pos-1)
    {
        p=p->pNext;
        ++i;
    }
    if(i>pos-1||NULL==p)
    {
        return false;
    }
    PNODE pNew=(PNODE)malloc(sizeof(NODE));
    if(NULL==pNew)
    {
        printf("新结点的动态内存分配失败!\n");
        exit(-1);
    }
    pNew->data=val;
    PNODE q=p->pNext;
    p->pNext=pNew;
    pNew->pNext=q;
    return true;
}

bool delete_list(PNODE pHead, int pos, int * pVal)
{
    int i=0;
    PNODE p=pHead;
    while(i<pos-1&&NULL!=p)
    {
        p=p->pNext;
        ++i;
    }
    if(i>pos-1||NULL==p)
    {
        return false;
    }
    PNODE q=p->pNext;
    *pVal=q->data;
    //删除p结点之后一个位置的结点
    p->pNext=p->pNext->pNext;
    free(q);
    q=NULL;
}

写在最后

        以上所有的操作细节与代码具体实现的思想已叙述完毕,希望对各位读者有所帮助。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

grx_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值