数据结构学习笔记——线性表之单链表(c语言实现)

1.概念

链式存储结构:是指把数据元素存放在任意内存未被占用的存储单元里,这组存储单元可以是连续的,也可以是不连续的。
大概就是这样:
在这里插入图片描述
因此,为了表示每个数据元素a1,与其直接后继数据元素 a2 之间的逻辑关系,对数据元素a来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。
对此有如下几个概念:

数据域指针域指针(链)头指针
存储数据元素信息的域存储直接后继位置的域指针域中存储的信息指向第一个结点的指针,具有标识作用常冠以链表名字,是链表的必要元素
结点链表单链表头结点
数据域与指针域的结合n 个结点按一定逻辑次序的链结链表的每个结点中只包含一个指针域放在第一元素结点之前,数据域一般无意义,非必要

下图即为一个单链表:
在这里插入图片描述

2.实现

完整代码下载地址:https://download.csdn.net/download/luotuoxiansheng/10756421

(1)建立结点结构

在这里插入图片描述

typedef struct SlNode
{
    ElemType1 name[DATA1LENGTH];  //创建数组存储空间
    ElemType2 number[DATA2LENGTH];
    ElemType2 length;             //标识表长
    struct SlNode *next;          //创建指向结点的指针
}SlNode,*LinkList;
(2)创建表单

创建结点数据并利用尾插法依次插入链表,形成初始的单链表

示例代码:

void CreateList(SlNode *L)
 {
     SlNode *p,*newnode;
     L->length=0;
     p=L;
     char flag='y';
    puts("创建表单:");
	while(flag=='Y'||flag=='y'){
        newnode=(LinkList)malloc(sizeof(SlNode));
		printf("name:");
		scanf("%s",newnode->name);
		printf("number:");
		scanf("%d",newnode->number);

        //节点插入(尾部)
		newnode->next=NULL;
        p->next=newnode;
        p=newnode;
        L->length++;

		getchar();//等待输入完成后的回车键
		printf("继续输入?(y/n)");
		scanf("%c",&flag);
	}   
 }

结果演示:
在这里插入图片描述

(3)增:在第i个位置插入数据

在这里插入图片描述
示例代码:

void SListInsert(SlNode *L)
{
    int i;
    int j=1,n=1;
    SlNode *p,*newnode;
    p=L;
    printf("在第几个位置插入?请输入:");
    scanf("%d",&i);
    if (i>(L->length+1)||i<j)
    {
      printf("error!节点不存在!\n");
      return;
    }
    while (j<i) //顺序查询,不是该节点就查询下一个点
    {
       p=p->next;
       j++;
    }
    
    //找到插入位置后创建结点数据
    newnode=(LinkList)malloc(sizeof(SlNode));
    printf("name: ");
    scanf("%s",newnode->name);
    printf("number: ");
    scanf("%d",newnode->number);
    
    //插入
    newnode->next=p->next;
    p->next=newnode;

    if(i==L->length+1)//如果是在尾部插入,则让newnode->next=NULL;
    newnode->next=NULL;

    L->length++;
}

结果演示:
可在任意位置插入结点。依次在尾部、头部、第i个结点处插入:
尾插:
在这里插入图片描述
头插:
在这里插入图片描述
第3个结点处:
在这里插入图片描述

(4)删:删除第i个数据

在这里插入图片描述
示例代码:

Status SListDelete(SlNode *L)
{
    int j=1;
    int i;
    SlNode *p=L;
    SlNode *q;
    printf("请输入Nob:");
    scanf("%d",&i);
    if (i>(L->length)||i<j)
    {
      printf("error!节点不存在!\n");
      return 0;
    }
    while (j<i) //顺序查询,不是该节点就查询下一个点
    {
       p=p->next;
       j++;
    }
        //删除q节点
        q=p->next;
        p->next=q->next;
        free(q);
        --(L->length);
        return 1;
}

结果演示:
删除第三个结点
在这里插入图片描述

(5)改:更改数据

在这里插入图片描述
示例代码:

  Status SListUpdate(SlNode *L)
{
    int j=1;
    int i;
    SlNode *p=L->next;
    printf("请输入Nob:");
    scanf("%d",&i);
    if (i>(L->length)||i<j)
    {
      printf("error!节点不存在!\n");
      return 0;
    }
    while (j<i) //顺序查询,不是该节点就查询下一个点
    {
       p=p->next;
       j++;
    }
        printf("新name:");
		scanf("%s",p->name);
		printf("新number:");
		scanf("%d",p->number);

        return 1;
}

结果演示:
更改第三个结点数据
在这里插入图片描述

(6)查:查找数据

在这里插入图片描述

本例程中若要查找字符串类型的数据,在c语言中应使用strcmp()函数去匹配查找,不能直接使用“==”匹配,笔者因为这个问题在这出现了很多错误。

示例代码:

SlNode *SListGet(SlNode *L)
{
    int n;
    ElemType2 Nob;
    int ch;
    SlNode *p;
    SlNode *input;
    SlNode *get;
    p=L->next;
    input=(LinkList)malloc(sizeof(SlNode));//创建结点用于存储输入数据
    printf("查找项(1.Nob/2.name/3.number):");
    scanf("%d",&ch);
    switch(ch)
    {
        case 1:{
                printf("请输入Nob:");
                scanf("%d",&Nob);
                n=1;
                  while(n<=L->length)
                {
                    if(Nob==n)
                        {
                           get=p;
                           return get;
                        }

                    p=p->next;
                    n++;
                }  
                 printf("没有此数据!\n");return 0;
        };break;

        case 2:{
                n=1;
                printf("请输入name:");
                scanf("%s",input->name);
                while(n<=L->length)
                {
                    if(!strcmp(p->name,input->name))//若两个字符串相等
                        {
                           get=p;
                           return get;//找到就返回
                        }
                    p=p->next;
                    n++;
                }
                 printf("没有此数据!\n");return 0;
        };break;

        case 3:{
                n=1;
                printf("请输入number:");
                scanf("%d",input->number);
                 while(n<=L->length)
                {
                    if(*p->number==*input->number)
                        {
                           get=p;
                           return get;//找到就返回
                        }
                    p=p->next;
                    n++;
                }
                 printf("没有此数据!\n");return 0;
        };break;
        default: printf("错误!没有这个选项!\n");
    }
}

结果演示:
按序号查找:
在这里插入图片描述
按name查找:
在这里插入图片描述
按number查找:
在这里插入图片描述

(7)排序:对表单按照number升序重新排序(冒泡排序法)

排序方法多种多样,有两篇博文对各种排序方法都有不错的介绍和实现:
https://www.cnblogs.com/eniac12/p/5329396.html#s1
https://www.cnblogs.com/eniac12/p/5332117.html

此处选用冒泡排序,算法示意图如下:
在这里插入图片描述

在单链表中使用冒泡排序关键在于相邻两个结点的交换:
在这里插入图片描述
交换后p往后退一格:
在这里插入图片描述
示例代码:

 void SListSort(SlNode *L)
{
    int i,j;
    SlNode *pre=L;
    SlNode *p=L->next;
    SlNode *tmp;

    for (i=0;i<L->length-1;i++)
    {
        pre=L;
        p=L->next;
        for (j=0;j<L->length-1-i;j++)
        {
            if (*(p->number)>*(p->next->number))
            {
                //交换节点
                pre->next=p->next; 
				p->next = p->next->next;
                pre->next->next=p;
                p=pre->next;//更新p的位置
            }
            //p再前进一个结点
            p=p->next; 
			pre=pre->next;
        }
    }
    PrintList(L);//打印表单
}

结果演示:
在这里插入图片描述

(8)其他

表单打印和清空整表的内容不再详细写出,详见完整代码,下载地址:https://download.csdn.net/download/luotuoxiansheng/10756421

3.优劣势分析

比较顺序表,单链表更加灵活,且存储空间大小不确定。若需要频繁插入和删除时适合使用单链表,以及当线性表中的元素个数变化较大或者根本不知道有多大时宜采用单链表结构。

以上就是对单链表的学习和分享

  • 11
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值