线性表链式存储(单链表)

理解链式存储

为了表示数据元素与直接后继数据元素的关系,每个数据元素除了保存自己的信息之外,还需要存储直接后继的信息。

那么我们应该怎么做呢?首先我们应该在每个数据结点中包含一个指针域(存储直接后继结点的头部地址)。

 

                       

头部结点:链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息

数据结点:链表中的数组元素结点,包含了下一个数据结点的指针和自身信息

尾结点:链表中最后一个数据元素结点,后继结点为空。

//LinkList.h
#pragma once
typedef void LinkList;

//数据元素结点
typedef struct tag_LinkListNode
{
    struct tag_LinkListNode *next;//指针域
}TLinkListNode;

//创建链表
LinkList *LinkList_Creat();
//销毁链表
void LinkList_Destroy(LinkList*list);
//清空链表初始化链表
void LinkList_Clear(LinkList *list);
//获取链表长度
int LinkList_GetLength(LinkList *list);
//插入结点
int LinkList_inster(LinkList *list, TLinkListNode *node, int pos);
//获取指定位置结点
TLinkListNode *LinkList_Get(LinkList *list, int pos);
//删除指定位置结点
TLinkListNode *LinkList_Delete(LinkList *list, int pos);

 

插入元素的操作

假设pos = 3表示在链表中下标为3的位置插入一个节点。

提供一个辅助指针current,通过循环跳转到pos-1的位置,current->next是current当前指向结点的后继结点,那么我们应该怎么操作呢?

首先我们应该把Node结点的后继指针指向current当前结点的后继结点,其次current的后继指针指向插入的结点,这样就完成了链接。

node->next = current->next

curren->next = node

获取指定元素的操作

这里我们需要注意,指向头部结点的指针移动n次和第n个元素之间的关系

假设我们要获取pos = 3(索引下标)位置上的结点,那么辅助指针current通过循环跳转应该跳转到pos-1的位置上,这样我们要获取的结点应该是current后继指针指向的结点:current->next

删除指定位置元素操作

删除指定结点同样要注意指向头部结点的指针移动n次和第n个元素之间的关系

假设我们要删除pos = 3位置上的结点,我们需要让辅助指针current通过循环跳转到pos-1的位置上

首先提供一个辅助指针结点用来存放要删除的结点node,其次让辅助指针current的后继指针指向要删除结点node的后继结点。

node =  current->next;

current->next = node->next

//LinkList.c
#pragma warning(disable : 4996)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "LinkList.h"

//链式线性表
typedef struct tag_LinkList
{
    TLinkListNode header;//头部结点
    int length;//线性表长度
}TLinkList;

//创建链式线性表
LinkList * LinkList_Creat()
{
    TLinkList *list = NULL;
    list = (TLinkList *)malloc(sizeof(TLinkList));//给链式线性表分配堆内存
    if (list == NULL)
    {
        printf("LinkList_Creat err: list = NULL");
        return NULL;
    }
    memset(list, 0, sizeof(TLinkList));//链式线性表初始化(分配了内存要负责)
    list->length = 0;
    list->header.next = NULL;
    return list;
}
//销毁链式线性表
void LinkList_Destroy(LinkList * list)
{
    if (list == NULL)
    {
        printf("LinkList_Destroy err: list = NULL");
        return;
    }
    free(list);//直接释放链式线性表堆内存
    printf("LinkList_Destroy finished \n");
    return;
}
//清空线性表
void LinkList_Clear(LinkList * list)
{
    TLinkList *temp = NULL;
    if (list == NULL)
    {
        printf("LinkList_Clear err: list = NULL");
        return;
    }
    temp = (TLinkList *)list;//类型转换
    temp->length = 0;//重置长度
    temp->header.next = NULL;//头结点置空
    return;
}
//获取链表长度
int LinkList_GetLength(LinkList * list)
{
    TLinkList *temp = NULL;
    if (list == NULL)
    {
        printf("LinkList_GetLength err: list = NULL");
        return -1;
    }
    temp = (TLinkList *)list;//类型转换
    return temp->length;//返回链表长度
}
//在指定位置插入结点
int LinkList_inster(LinkList * list, TLinkListNode * node, int pos)
{
    TLinkList *temp = NULL;
    int i = 0;
    if (list == NULL || node == NULL || pos < 0)
    {
        printf("LinkList_inster err: list = NULL || node = NULL || pos < 0");
        return -1;
    }
    temp = (TLinkList *)list;//类型转换
    TLinkListNode * current = &(temp->header);//当前结点
    for (i = 0; i < pos && node->next != NULL; i++)//跳转到插入位置的前一个结点位置处
    {
        current = current->next;
    }
    node->next = current->next;//插入节点的后继指针指向当前结点的后继结点
    current->next = node;//当前结点的后继指针指向要插入的结点
    temp->length++;//链表长度+1
    return 0;
}
//获取链表指定位置结点
TLinkListNode * LinkList_Get(LinkList * list, int pos)
{
    TLinkList *temp = NULL;
    int i = 0;
    if (list == NULL  || pos < 0)
    {
        printf("LinkList_Get err: list = NULL ||  pos < 0");
        return NULL;
    }
    temp = (TLinkList *)list;//类型转换
    TLinkListNode * current = &(temp->header);//当前结点
    for (i = 0; i < pos ; i++)//循环跳转到需要获取结点的前一个结点处
    {
        current = current->next;
    }
    return current->next;//返回需要获取的结点
}
//删除链表指定位置结点
TLinkListNode * LinkList_Delete(LinkList * list, int pos)
{
    TLinkList *temp = NULL;
    int i = 0;
    if (list == NULL || pos < 0)
    {
        printf("LinkList_Get err: list = NULL ||  pos < 0");
        return NULL;
    }
    temp = (TLinkList *)list;//类型转换
    TLinkListNode *current = &(temp->header);//辅助指针指向头部结点
    TLinkListNode *ret = NULL;//辅助指针存放需要删除的结点
    for (i = 0; i < pos; i++)//循环跳转到要删除几点的前一个结点处
    {
        current = current->next;
    }
    ret = current->next;//临时存放要删除的结点
    current->next = ret->next;//当前结点的后继指针指向要删除结点的后继节点处
    temp->length--;//链表长度-1
    return ret;//返回要删除的结点
}
//测试代码
#pragma warning(disable : 4996)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "LinkList.h"

typedef struct tag_Teacher
{
    TLinkListNode node;
    int age;
    char *name;
}Teacher;

int main(int argc, char** argv)
{
    Teacher t1, t2, t3, t4, t5;
    t1.age = 20;
    t1.name = "zhangsan";
    t2.age = 21;
    t2.name = "lisi";
    t3.age = 22;
    t3.name = "wangwu";
    t4.age = 23;
    t4.name = "zhaoliu";
    t5.age = 24;
    t5.name = "wangqi";

    LinkList *list = NULL;
    list = LinkList_Creat();
    if (list == NULL)
    {
        printf("LinkList_Creat err: list = NULL");
        return -1;
    }
    int i, ret = 0;
    //尾插法
    ret = LinkList_inster(list, (TLinkListNode *)&t1, LinkList_GetLength(list));
    ret = LinkList_inster(list, (TLinkListNode *)&t2, LinkList_GetLength(list));
    ret = LinkList_inster(list, (TLinkListNode *)&t3, LinkList_GetLength(list));
    ret = LinkList_inster(list, (TLinkListNode *)&t4, LinkList_GetLength(list));
    ret = LinkList_inster(list, (TLinkListNode *)&t5, LinkList_GetLength(list));

    printf("LinkList length = %d\n", LinkList_GetLength(list));

    for (i = 0; i < LinkList_GetLength(list); i++)
    {
        Teacher *t = (Teacher *) LinkList_Get(list, i);
        printf("age = %d,name = %s\n", t->age, t->name);
    }
    system("pause");
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章