数据结构之线性表的链式存储

线性表的链式存储结构(单链表)

这里是数据结构个人学习的笔记记录,如有问题欢迎指正说明

单链表的定义

n个结点链结成一个链表。每个结点由数据域和指针域两部分组成,在此处我们之研究结点只含一个指针域的链表,即单链表。
单链表定义

我们把链表中的第一个结点的存储位置叫做头指针,整个链表的存取必须从头指针开始。为了方便操作,我们还可以在单链表的第一个结点前附设一个结点,称为头结点。注意头结点不是必不可少的。头结点和头指针的区别如下图:
头指针和头结点的异同

单链表的相关操作实现

基础宏定义

使用这些宏定义能增强代码的阅读性和通用性

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20

typedef int Status;/*函数结果状态代码*/
typedef int ElemType;/*待存储数据的数据类型*/

基本结构体

typedef struct Node
{
    ElemType data;
    struct Node *next;
}Node;
typedef Node *LinkList;

初始化

/* 初始化 */
Status InitList(LinkList *L)
{
    *L=(LinkList)malloc(sizeof(Node));
    if(!(*L))
    return ERROR;
    (*L)->next=NULL;/*指针域为空*/

    return OK;
}

依次对单链表中的每个数据元素输出

/* 依次对L的每个数据元素输出 */
Status ListTraverse(LinkList L)
{
    LinkList p=L->next;
    while(p)
    {
        visit(p->data);//vist函数为输出值
        p=p->next;
    }
    printf("\n");
    return OK;
}

返回单链表中元素的个数

/*返回L中数据元素个数*/
int ListLength(LinkList L)
{
    int i=0;
    LinkList p=L->next;
    while(p)
    {
        i++;
        p=p->next;
    }
    return i;
}

在单链表中指定位置之前插入新的数据元素

插入操作

/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList *L,int i,ElemType e)
{
    int j=1;
    LinkList p,s;
    p=*L;
    while(p&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i)
    return ERROR;
    s=(LinkList)malloc(sizeof(Node));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return OK;
}

删除线性表的指定位置的数据元素

在这里插入图片描述

/* 删除线性表的指定位置的数据元素 */
Status ListDelete(LinkList *L,int i,ElemType *e)
{
    int j=1;
    LinkList p,q;
    p=*L;
    while(p->next&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!(p->next)||j>i)
    return ERROR;
    q=p->next;
    p->next=q->next;
    *e=q->data;
    free(q);
    return OK;
}

返回单链表中第一个与指定数据相符的数据的位序

/* 返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int LocateElem(LinkList L,ElemType e)
{
    int i=0;
    LinkList p=L->next;
    while(p)
    {
        i++;
        if(p->data==e)
        return i;
        p=p->next;
    }
    return 0;
}

返回指定位置的值

/* 用e返回L中第i个数据元素的值 */
Status GetElem(LinkList L,int i,ElemType *e)
{
    int j=1;
    LinkList p;
    p=L->next;
    while(p&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i)
    return ERROR;
    *e=p->data;
    return OK;
}

将单链表重置为空表

/* 将L重置为空表 */
Status ClearList(LinkList *L)
{
    LinkList p,q;
    p=(*L)->next;
    while(p)
    {
        q=p->next;
        free(p);
        p=q;
    }
    (*L)->next=NULL;
    return OK;
}

头插的实现

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
void CreateListHead(LinkList *L,int n)
{
    LinkList p;
    int i;
    srand(time(0));
    *L=(LinkList)malloc(sizeof(Node));
    (*L)->next=NULL;
    for(i=0;i<n;i++)
    {
        p=(LinkList)malloc(sizeof(Node));
        p->data=rand()%100+1;
        p->next=(*L)->next;
        (*L)->next=p;
    }
}

尾插的实现

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateListTail(LinkList *L, int n) 
{
	LinkList p,r;
	int i;
	srand(time(0));                   
	*L = (LinkList)malloc(sizeof(Node)); 
	r=*L;                           
	for (i=0; i<n; i++) 
	{
		p = (Node *)malloc(sizeof(Node)); 
		p->data = rand()%100+1;     
		r->next=p;                        
		r = p;                          
	}
	r->next = NULL;                     
}

链式存储的代码实现

#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<math.h>
#include<time.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20

typedef int Status;
typedef int ElemType;

typedef struct Node
{
    ElemType data;
    struct Node *next;
}Node;
typedef Node *LinkList;

Status visit(ElemType c)
{
    printf("%d ",c);
    return OK;
}
/* 初始化链式线性表 */
Status InitList(LinkList *L)
{
    *L=(LinkList)malloc(sizeof(Node));
    if(!(*L))
    return ERROR;
    (*L)->next=NULL;

    return OK;
}
/* 初始条件:链式线性表L已存在。操作结果:将L重置为空表 */
Status ClearList(LinkList *L)
{
    LinkList p,q;
    p=(*L)->next;
    while(p)
    {
        q=p->next;
        free(p);
        p=q;
    }
    (*L)->next=NULL;
    return OK;
}
/* 初始条件:链式线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(LinkList L)
{
    int i=0;
    LinkList p=L->next;
    while(p)
    {
        i++;
        p=p->next;
    }
    return i;
}
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
Status GetElem(LinkList L,int i,ElemType *e)
{
    int j=1;
    LinkList p;
    p=L->next;
    while(p&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i)
    return ERROR;
    *e=p->data;
    return OK;
}
/* 初始条件:链式线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int LocateElem(LinkList L,ElemType e)
{
    int i=0;
    LinkList p=L->next;
    while(p)
    {
        i++;
        if(p->data==e)
        return i;
        p=p->next;
    }
    return 0;
}
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList *L,int i,ElemType e)
{
    int j=1;
    LinkList p,s;
    p=*L;
    while(p&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i)
    return ERROR;
    s=(LinkList)malloc(sizeof(Node));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return OK;
}
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(LinkList *L,int i,ElemType *e)
{
    int j=1;
    LinkList p,q;
    p=*L;
    while(p->next&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!(p->next)||j>i)
    return ERROR;
    q=p->next;
    p->next=q->next;
    *e=q->data;
    free(q);
    return OK;
}
/* 初始条件:链式线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status ListTraverse(LinkList L)
{
    LinkList p=L->next;
    while(p)
    {
        visit(p->data);
        p=p->next;
    }
    printf("\n");
    return OK;
}
/*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
void CreateListHead(LinkList *L,int n)
{
    LinkList p;
    int i;
    srand(time(0));
    *L=(LinkList)malloc(sizeof(Node));
    (*L)->next=NULL;
    for(i=0;i<n;i++)
    {
        p=(LinkList)malloc(sizeof(Node));
        p->data=rand()%100+1;
        p->next=(*L)->next;
        (*L)->next=p;
    }
}
/*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateListTail(LinkList *L, int n) 
{
	LinkList p,r;
	int i;
	srand(time(0));                   
	*L = (LinkList)malloc(sizeof(Node)); 
	r=*L;                           
	for (i=0; i<n; i++) 
	{
		p = (Node *)malloc(sizeof(Node)); 
		p->data = rand()%100+1;     
		r->next=p;                        
		r = p;                          
	}
	r->next = NULL;                     
}
void ListTest()
{        
    LinkList L;
    ElemType e;
    Status i;
    int j,k;
    i=InitList(&L);
    printf("初始化L后:ListLength(L)=%d\n",ListLength(L));
    for(j=1;j<=5;j++)
            i=ListInsert(&L,1,j);
    printf("在L的表头依次插入1~5后:L.data=");
    ListTraverse(L); 
    printf("ListLength(L)=%d \n",ListLength(L));

    i=ClearList(&L);
    printf("清空L后:ListLength(L)=%d\n",ListLength(L));

    for(j=1;j<=10;j++)
            ListInsert(&L,j,j);
    printf("在L的表尾依次插入1:10后:L.data=");
    ListTraverse(L); 
    printf("ListLength(L)=%d \n",ListLength(L));

    ListInsert(&L,1,0);
    printf("在L的表头插入0后:L.data=");
    ListTraverse(L); 
    printf("ListLength(L)=%d \n",ListLength(L));

    GetElem(L,5,&e);
    printf("第5个元素的值为:%d\n",e);
    for(j=3;j<=4;j++)
    {
            k=LocateElem(L,j);
            if(k)
                    printf("第%d个元素的值为%d\n",k,j);
            else
                    printf("没有值为%d的元素\n",j);
    }
    
    k=ListLength(L); /* k为表长 */
    for(j=k+1;j>=k;j--)
    {
            i=ListDelete(&L,j,&e); /* 删除第j个数据 */
            if(i==ERROR)
                    printf("删除第%d个数据失败\n",j);
            else
                    printf("删除第%d个的元素值为:%d\n",j,e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L); 

    j=5;
    ListDelete(&L,j,&e); /* 删除第5个数据 */
    printf("删除第%d个的元素值为:%d\n",j,e);

    printf("依次输出L的元素:");
    ListTraverse(L); 

    i=ClearList(&L);
    printf("\n清空L后:ListLength(L)=%d\n",ListLength(L));
    CreateListHead(&L,20);
    printf("整体创建L的元素(头插法):");
    ListTraverse(L); 
    
    i=ClearList(&L);
    printf("\n删除L后:ListLength(L)=%d\n",ListLength(L));
    CreateListTail(&L,20);
    printf("整体创建L的元素(尾插法):");
    ListTraverse(L); 
}
int main()
{
    ListTest();

    return 0;
}

样例测试输出

初始化L后:ListLength(L)=0
在L的表头依次插入1~5后:L.data=5 4 3 2 1
ListLength(L)=5
清空L后:ListLength(L)=0
在L的表尾依次插入1:10后:L.data=1 2 3 4 5 6 7 8 9 10
ListLength(L)=10
在L的表头插入0后:L.data=0 1 2 3 4 5 6 7 8 9 10
ListLength(L)=11
第5个元素的值为:4
第4个元素的值为3
第5个元素的值为4
删除第12个数据失败
删除第11个的元素值为:10
依次输出L的元素:0 1 2 3 4 5 6 7 8 9
删除第5个的元素值为:4
依次输出L的元素:0 1 2 3 5 6 7 8 9
清空L后:ListLength(L)=0
整体创建L的元素(头插法):87 50 42 93 84 66 26 28 64 76 46 68 59 87 22 2 25 39 66 33
删除L后:ListLength(L)=0
整体创建L的元素(尾插法):33 66 39 25 2 22 87 59 68 46 76 64 28 26 66 84 93 42 50 87

链式存储的优缺点

优点:存储空间可自由扩充
插入、删除等操作不必移动数据,修改效率较高
缺点:读写效率不高,必须采用顺序读取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ALuoJi

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

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

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

打赏作者

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

抵扣说明:

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

余额充值