单链表专题

单链表涉及到初步的动态规划,以前所用的数组等都是静态存储某些东西,通过单链表的建立我们接触一下动态规划,这将及其节省存储空间提高空间利用率。

每个链表都少不了指针头指针指向单链表的第一个节点,是链表操作的唯一入口。
单链表的最后一个结点没有后继结点因此指针域为空

例如一个简单的结点:

struct Node             //结点的结构体类型定义
{
    int data;           //数据域
    struct Node *next;  //指针域,类型为struct Node,指向下一个结点的地址
};

对于同一个链表中每个结点的类型都是一致的,因此结点中存放下一个结点地址的指针变量类型也是该结点类型。

可用该节点类型定义一个结点a :

typedef struct Node NODE;    
NODE a;                  //定义结点a
a.data=80;                //给两个领域赋值
a.next=NULL;

例子:
一个简单的单向链表实现链表的建立和输出;

#include<stdio.h>
typedef struct Node
{
    int data;
    struct Node *next;
}NODE;
void main()
{
    NODE a,b,c;
    NODE *h,*p;
    a.data=1;b.data=2;c.data=3;
    h=&a;
    a.next=&b;
    b.next=&c;
    c.next='\0';
    p=h;
    while(p!=NULL)
    {
        printf("%d",p->data);
        p=p->next;
    }
    printf("\n");
}

通过上述三条指令就建立了一个简单的链表接下去通过指向该链表的头指针就可以实现对链表的操作了。
链表的访问一般从头指针开始按照逻辑的顺序进行访问。
链接到一起的结点都是通过事先定义由系统内存开辟了的互不联系的存储单元,这样的链表成为静态链表,而实际中更需要的是动态链表,即每个存储单元都是由动态存储分配而来的,这是重点。

《动态内存分配》
前面讲过,链表的结构是动态分配储存的,即在需要的时候才开辟一个结点的存储单元。
C语言库库函数提供了以下几种函数在头文件

NODE *p;
p=(NODE*)malloc(sizeof(NODE));

表示 分配一块存储空间,其大小为NODE长度,由于malloc返回值为void类型的,因此又将其强制转换为NODE类型指针,且把该赋给同类型指针变量p。
2。。calloc函数
原型为void calloc(unsigned n,unsigned size)
calloc可用于动态分配内存,分配n个长度为size的连续空间,函数返回为指向该区域起始地址的指针(基本类型为void)
用calloc函数可以为一维数组开辟动态存储空间。
3.。。free函数
原型void free(void *p)
作用是释放由p指向的内存分区,使这部分分区可以被其他变量使用。p是调用malloc或者calloc函数的返回值。free函数无返回值。

例子:

#include<stdio.h>
#include<stdlib.h>
struct student
{
    char name[20];
    float score;
};
typedef struct student STU;
int main()
{
    STU *pt;
    pt=(STU*)malloc(sizeof(STU));    //动态分配
    printf("please enter name;\n");
    scanf("%s",pt->name);
    printf("please enter score\n");
    scanf("%f",&pt->score);
    printf("%s:%.0f\n",pt->name,pt->score);
    free(pt);
    return 0;
}

单链表:
单链表的创建是指在程序执行的时候建立起一个个的结点,并将他们按照逻辑顺序连接成一串形成一个链表。
一般步骤:
(1)定义链表数据结构
(2)读取数据
(3)若读入的数据是有效的,则生成一个新的结点,即利用mallloc()函数向系统申请分配一个结点。
例子:

struct node *head;

head=(struct *node)malloc(sizeof(struct node));

(4)将数据存入结点的变量成员中。
(5)将新的结点插入到链表中
(6)判断是否有后续结点介入链表若有则转到步骤3,否则结束。
例如:建立一个有若干学生信息的单项链表,信息包括学号姓名一门课成绩以学号0标记结束
源程序:

#include<stdio.h>
#include<stdlib.h>
struct node
{
    int id;
    char name[20];
    int score;
    struct node *next;
};
typedef struct node SNODE;
SNODE *creat(SNODE *head)
{
    int id;
    char name[20];
    int score;
    SNODE *s;
    SNODE *r;
    head=(SNODE*)malloc(sizeof(SNODE));
    r=head;
    printf("输入学号:");
    scanf("%d",&id);
    while(id!=0)
    {
        printf("输入姓名");
        scanf("%s",name);
        printf("输入成绩");
        scanf("%d",&score);
        s=(SNODE*)malloc(sizeof(SNODE));  //申请新的结点

        //将数据存放在新的节点中
        {
            s->id=id;
            strcpy(s->name,name);
            s->score=score;
            r->next=s;

        }

        //指针移动
        r=s;
        //输入下一个数据
        printf("输入学号");
        scanf("%d",&id);
    }
    r->next='0';
    return head;
}
int main()
{
    SNODE *head;
    head=NULL;
    head=creat(head);
    return 0;
}

这个例子中自定义的creat函数中可以描述如下:
(1)建立头节点:先申请一个STU类型的结点,用head指针指向该结点,同时也用r指针指向它,这个结点作为头结点并不存放数据。
(2)读取数据,若数据有效则创建一个新的结点,用s指向该结点然后将数据存放在新的节点中,
接着通过语句r->next=s; r=s;将该结点与前一个结点连起来,然后使r指针取s指针的值。此时head指针的位置不变,而r指针和s指针则指向新的结点。
(3)继续读取数据,若有效则重复步骤(2)
(4)若输入学号为0,说明数据无效,推出循环,执行r->next=’0’,结束链表的建立过程。
//由此可见,判断此链表是否为空链表,可利用条件head->next===’\0’来判断。
本例子中设置了一个头节点head不存放任何数据,根据需要也可以不设头节点。
链表最后一个结点的指针域不需要存放地址的时候,就置’0’(即NULL),标志这链表的结束。

上述链表每个结点只有一个指针域,每个指针域存放着下一个结点的地址,这种链表只能从当前结点找到后继节点所以称“单向链表”。

主函数中先用指针head建立了一个空表,然后将其作为实参传递到creat函数中在creat函数里边建立了一个链表,其头指针始终是head,当链表建立完以后,create函数将返回该头指针,因此main函数中的head就成为一个单向链表的头指针了。这里creat函数的返回值是建立好链表的头指针。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值