线性表->单链表

单链表

链式存储的线性表又称之为单链表。他是通过一组任意的存储单元来存储线性表中的数据元素。为了建立起数据元素之间的线性关系,每个节点除了存放自身的数据信息外,还要一个指向其后继的指针。

利用单链表可以解决顺序表需要大量的连续存储空间的缺点,但是单链表附加指针域,也带来了浪费存储空间的缺点。由于单链表是离散的分布在存储空间中,所以单链表是非随机存取的。


通常为了操作方便,会给单链表的第一个之前附加一个节点,称之为头结点。头结点的数据域可以不设任何信息,但可以记录表长等信息。

引入头结点带来的两个有点:

  • 由于开始节点的位置被存放在头结点中,所以链表第一个位置上的操作和在表其他位置上的操作一致,无需进行特殊处理;
  • 无论链表是否为空,其头指针指向头结点的非空指针,因此空表和非空表的处理也就统一。带头单链表的判定空条件为L->next = =NULL



/************************************************************************************************
头指针:
            1,头指针是指链表指向第一个节点的指针,若链表的有头结点,则是指向头结点的指针
            2,头指针有标识作用,长用头指针冠以链表的名字
            3,无论链表是否为空,头指针均不能为空,头指针是链表的必要元素
头结点:
            1,头结点是为了操作的统一和方便而设立,放在第一个元素结点之前,其数据域一般无意义
            2,有了头结点,对在第一个结点前插入和删除第一个元素结点,其操作和其他元素的操作便统一
            3,头结点不一定是链表的必要元素
************************************************************************************************/

/**********************************单链表结构和顺序存储结构优缺点***************************************
存储分配方式:
            1,顺序存储结构用一段连续的存储单元依次存储线性表的数据元素
            2,单链表采用链式的存储结构,用一组任意的存储单元存放线性表元素

时间性能:
            1,查找: 顺序存储结构O(1)    单链表O(n)
            2,插入删除: 顺序存储结构要平均移动一半的元素, O(n)
                       单链表在查出某位置的指针后,插入删除均为O(1)

空间性能:
            1,顺序存储需要预先分配存储空间,分配大了浪费,小了容易发生上溢出
            2,单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制
************************************************************************************************/

#include <malloc.h>

#define MAXSIZE 20  //存储空间初始分配量
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int ElemType;   //ElemType 数据类型
typedef int Status;

typedef struct
{
    ElemType date;
    struct Node *next;
}Node,*LinkList;

//单链表的读取 O(n)
/************************************************************************************************
1,声明一个节点p指向链表的第一个节点,初始化j从1开始;
2,当j<i时,就遍历链表,p向后移动,不断指向下一个节点,j++;
3,若到链表末尾p为空,则说明第i个元素不存在;
4,否则查找成,返回节点p的数据
************************************************************************************************/

Status GetElem(LinkList L, int i, ElemType *e)
{
    int j;
    Node *p;    //声明一个结点

    p = L->next;    //让p指向链表的第一个节点
    j = 1;          //j为计数器

    while(p && j<i) //p不为空并且计数器j没有等于i,循环继续
    {
        p = p->next;    //移向下一结点
        ++j;            //计数加一
    }

    if( !p || j>i)      //第i个元素不存在
        return ERROR;

    *e = p->date;       //取得第i个元素

    return OK;
}


/************************************************************************************************
单链表的插入和删除算法,实际是由两部分组成:O(n)
1,遍历查找第i个元素
2,插入或者删除相应元素
************************************************************************************************/

//单链表的插入
/************************************************************************************************
1,声明结点p并指向链表第一个节点,初始化j从1开始;
2,当j<i,遍历链表,让p的指针向后移动,不断的指向下一节点,并且j++;
3,若到链表末尾,p为空,则说明i元素不存在;
4,否则查找成功,在系统中生成一个空节点s;
5,将元素e赋值给s->data;
6,单链表的插入标准语句 s->next = p->next; p->next = s;
7,返回成功 
************************************************************************************************/
Status ListInsert(LinkList *L, int i, ElemType e)
{
    int j;
    Node * p,*s;
    p = *L;

    j =1;

    while(p && j<i)     //寻找第i个结点
    {
        p = p->next;
        ++j;
    }

    if(!p || j>i)       //i节点不存在
        return ERROR;

    //s = (LinkList)malloc(sizeof(Node));
    s= (Node*)malloc(sizeof(Node));     //生成新节点, #include<malloc.h>

    s->date = e;                        //将值付给s->date
    s->next = p->next;                  //将p的后继赋给s的后继
    p->next = s;                        //将p的后继指向s

    return OK;
}

// 若要在p之前插入S,可以在插入后,对调两个元素内的数据信息

s->next = p->next;
tmp = s->data;
s->data = p->next;
p->next = tmp;


 //单链表删除
/************************************************************************************************
1,声明一个结点p指向链表的第一个节点,初始化j从1开始;
2,当j<i是,遍历整个链表,让p指针右移动,不断的指向向下的节点,++j;
3,若链表末尾为空,则说明i元素不存在
4,否则查找成功,将欲删除的节点p->next给q;
5,单链表标准删除语句,p->next = q->next;
6,将q节点的数据赋值给e,作为返回值;
7,释放q节点;
8,返回成功
************************************************************************************************/

Status ListDelet(LinkList *L, int i, ElemType *e)
{
    int j;
    Node *p,*q;

    p = *L;
    j = 1;

    while(p->next && j<i)   //遍历寻找第i个元素的前一元素,p->next为第i元素
    {
        p = p->next;
        ++j;
    }

    if(!(p->next) || j>i)
        return ERROR;   //元素不存在返回ERROR

    q = p->next;        //让q指向第i个元素
    p->next = q->next;  //p的后继指向q的后继
    *e = q->date;       //q的值赋给e,以便返回
    free(q);            //清除结点,释放内存
    return OK;
}


// 单链表整表创建
//从“空表”的初始状态起,依次建立各个节点,并逐个加入链表中

/************************************************************************************************
1,声明一个节点p和计数器i;
2,初始化空链表L;
3,让L的头结点的指针指向NULL,即建立一个带头结点的单链表;
4,循环创建链表 (头插法):
    生成新的结点赋值给p;
    生成数字赋值给p的数据域p->data;
    将p插入到头结点与前一新节点之间。
************************************************************************************************/
void CreateListHead(LinkList *L, int n)
{
    LinkList p;
    int i;
    *L = (LinkList)malloc(sizeof(Node));
    (*L)->next = NULL;                  //建立带头结点的单链表,并且头结点指针为空

    for( i= 0; i<n; i++)
    {
        p = (LinkList)malloc(sizeof(Node)); //生成新结点
        p->date = i;
        p->next = (*L)->next;   //结点插入到表头
        (*L)->next = p;
    }
}

//尾插法
void CreateListTail(LinkList *L, int n)
{
    LinkList p,q;
    int i;
    *L = (LinkList)malloc(sizeof(Node));//创建线性表头
    p = *L;                             //p指向线性表的尾部

    for( i = 0; i<n; i++)
    {
        q = (LinkList)malloc(sizeof(Node)); //生成新的结点
        q->date = i;
        p->next = q;                        //将尾部节点的指针指向新的结点
        p = q;                              //尾部节点指针后移
    }

    p->next = NULL;                         //链表结束
}

//单链表 整表删除
/************************************************************************************************
1,声明一个结点p和q
2,将第一个结点赋值给p;
3,循环
    将下一结点赋值给q;
    释放q;
    将q赋值给p;
************************************************************************************************/
Status ClearList(LinkList *L)
{
    LinkList p,q;
    p = (*L)->next;     //p指向第一个结点

    while(p)            //到末尾结点
    {
        q = p->next;    //记录下一结点
        free(p);        //释放当前结点
        p = q;          //当前指针后移
    }

    (*L)->next = NULL;  //头结点指针域设为空
    return OK;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值