数据结构——单链表实现

链式存储特点

在链式存储中,节点之间的存储单元地址可能是不连续的。链式存储中每个结点都包含两部分:存储元素本身的数据域和存储结点地址的指针域。结点中的指针指向的是下一个结点,也就是存储的下一个结点的地址。

链式存储的实现

1.创建链表

在创建链表时,头结点不存储数据,但可以保存链表的信息。

struct Header
{
    int length;//记录链表大小
    struct Node *next; //指向第一个结点的指针
};

存储数据的结点包含两部分内容:数据域和指针域。

struct Node
{
    int data; //数据域
    struct Node *next; //指向下一个结点的指针
};

为了方便定义,将两个struct 用typedef重新定义:

typedef struct Node List; //节点
typedef struct Header pHead; //头节点

创建链表时,只需要创建一个头结点,每存储一个元素就分配一个存储单元,然后将存储单元的地址保存在上一个结点:

pHead* creatList()
{
    pHead* ph=(pHead *)malloc(sizeof(pHead)); //为头结点分配内存
    ph->length=0; //为头结点初始化,此时链表长度为0
    ph->next=NULL; 
    return ph; //将头结点地址返回
} 

2.获取链表大小

//获取链表的大小
int Size(pHead* ph)
{
    if(ph==NULL)
    {
        printf("传入参数有误!");
    }
    return ph->length;
}

3.插入元素

在链表中插入元素时要比在顺序表中快。比如在pos位置插入,则先断开pos-1与pos的链接,然后将pos-1结点的指针指向val结点,将val结点的指针指向pos。

//插入元素,在pos位置插入元素val
void Insert(pHead* ph,int pos,int val)
{
    if(ph==NULL || pos<0 || pos>ph->length)
    {
        printf("传入参数有误!");
        return;
    }
    //首先将值val保存在一个结点中
    List *pval=(List *)malloc(sizeof(List)); 
    pval->data=val;
    List *pCur=ph->next;
    if(pos==0) //插在首节点
    {
        ph->next=pval;
        pval->next=pCur;
    }
    else
    {
        for(int i=1;i<pos;i++)
        {
            pCur=pCur->next;
        }
        pval->next=pCur->next;
        pCur->next=pval;
    }
    ph->length++; //长度加1
    return;
}

4.查找某个元素

查找链表中的某个元素,其效率没有顺序表高,因为不管查找的元素在哪个位置,都需要将它前面的元素都全部遍历才能找到它。

//查找某个元素,并返回它的结点
List* find(pHead* ph,int val)
{
    if(ph==NULL)
    {
        printf("输入参数有误");
        return NULL;
    }
    //遍历链表来查找元素
    List* pTmp=ph->next;
    do
    {
        if(pTmp->data==val)
        {
            return pTmp;
        }
        pTmp=pTmp->next;
    }while(pTmp->next!=NULL);
    printf("没有值为%d的元素\n",val);
    return NULL;
}

5.删除元素

在删除元素时,首先将被删除元素与上下结点之间的链接断开,然后将这两个上下结点重新链接。

//删除节点,删除值为val的元素,删除成功,返回删除的元素
void Delete(pHead * ph,int val)
{
    if(ph==NULL)
    {
        printf("传入参数有误");
        return;
    }
    List* pval=find(ph,val);
    if(pval==NULL)
    {
        printf("没有找到值为%d的元素\n",val);
        free(pval); //释放结点
        return;
    }

    List* pRe=ph->next;
    List* pCur=NULL;
    if(pRe->data==val) //如果删除的是第一个节点
    {
        ph->next=pRe->next;
        ph->length--;
        free(pRe); //释放结点
        return;
    }
    else
    {
        for(int i=0;i<ph->length;i++)
        {
            pCur=pRe->next;
            if(pCur->data==val)
            {
                pRe->next=pCur->next;
                ph->length--;
                return;
            }
            pRe=pRe->next;
        }
        free(pCur); //释放结点
    }
    return;
}

6.销毁链表

销毁链表时,将链表中每个元素结点释放,头结点可以释放,也可以保留,将其置为初始化状态。

//销毁链表
void Destroy(pHead *ph)
{
    List* pCur=ph->next;
    List* pTmp;
    if(pCur==NULL)
    {
        printf("传入参数有误");
    }
    while(pCur->next!=NULL)
    {
        pTmp=pCur->next;
        free(pCur); //将结点释放
        pCur=pTmp;
    }
    ph->length=0; //初始化头结点
    ph->next=NULL; 
    printf("链表已销毁!\n");
}

7.遍历打印链表

//遍历打印链表
void print(pHead * ph)
{
    List * pTmp=ph->next;
    if(ph==NULL)
    {
        printf("传入参数有误");
    }
    while(pTmp!=NULL)
    {
        printf("%d ",pTmp->data);
        pTmp=pTmp->next;
    }
    printf("\n");
}

8.样例测试

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//所有函数声明
pHead* creatList(); //创建链表
int Size(pHead* ); //获取链表的大小
void Insert(pHead*,int,int); //插入元素
List* find(pHead*,int); //查找某个元素
void Delete(pHead*,int); //删除节点
void Destroy(pHead*); //销毁链表
void print(pHead*); //遍历打印链表

int main()
{
    List * ret;
    pHead * ph=creatList();
    int arr[10]={1,2,3,4,5,6,7,8,9,0};
    for(int i=0;i<10;i++)
    {
        Insert(ph,0,arr[i]);
    }

    printf("链表长度:%d\n",Size(ph));
    print(ph);
    printf("删除链表中的节点\n");
    int num;
    scanf("%d",&num);
    Delete(ph,num);
    printf("元素删除成功,删除元素%d后,链表中元素为:\n",num);
    print(ph);

    ret=find(ph,3);
    if(ret)
    {
        printf("get!\n");
    }
    else
    {
        printf("No!\n");
    }
    Destroy(ph); 
    return 0;
}

结果:

链表长度:10
0 9 8 7 6 5 4 3 2 1
删除链表中的节点
2
元素删除成功,删除元素2后,链表中元素为:
0 9 8 7 6 5 4 3 1
get!
链表已销毁!

猜你喜欢

转载自blog.csdn.net/qq_41822647/article/details/85284196
今日推荐