欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

单链表 数据结构 C语言

程序员文章站 2022-05-26 11:35:27
...

单链表-有头结点

环境:VisualStudio2019
操作

  • 初始化 + 判断表是否为空
  • 创表(图解)
    – 头插法
    – 尾插法
  • 打印单链表 + 求表长
  • 查找
    – 按位查找
    – 按值查找
  • 插入(图解)
    – 后插(在第i个位置插入元素e)
    – 前插(在第i个结点插入)
  • 删除(图解)
    – 按位删除(删除第i个位置的元素)
    – 按结点删除(删除第i个结点的元素)

头文件

#include<stdio.h>
#include<stdbool.h>

void Cut(); //分割线

//初始化
bool InitList(LinkList* L); //初始化(没用到,包含在创表里了)
bool Empty(LinkList L);//判断表是否为空(没用到)

//创表
LinkList HeadCreate(LinkList* L);
LinkList TailCreate(LinkList* L);
void Show(LinkList L);
int Length(LinkList L);

//查找
LNode* GetElem(LinkList L, int i);
int LocateElem(LinkList L, int e);

//插入
bool InsertNextNode(LNode* p, int e); //被ListAfterInsert调用
bool ListAfterInsert(LinkList* L, int i, int e);
bool InsertFormerNode(LNode* p, int e); //被ListBeforeInsert调用
bool ListBeforeInsert(LinkList* L, int i, int e);

//删除
bool ListOrderDelete(LinkList* L, int i);
bool DeleteNode(LNode* p); //被ListNodeDelete调用
bool ListNodeDelete(LinkList* L, int i);

typedef struct LNode  //单链表节点类型
{
    int data;      //存放数据元素
    struct LNode* next;  //指向下个节点的指针

} LNode, *LinkList;//给LNode两个名字

主函数

int main(void)
{
	LinkList L;
	int i = 1;
	int e = 1;

	printf("================开始=================\n");

	printf("请输入向链表中插入的值,以999作为结束:\n");
	HeadCreate(&L);                                  //创表:头插法
	printf("链表元素是:");
	Show(L);
	Cut();

	printf("请输入向链表中插入的值,以999作为结束:\n");
	TailCreate(&L);                                  //创表:尾插法
	printf("链表元素是:\n");
	Show(L);
	printf("链表当前长度是:%d",Length(L));
	Cut();
	
	printf("您想查看第几个位置的元素?");
	scanf_s("%d", &i);
	LNode* p = GetElem(L, i);                        //查找:按位查找
	printf("查询结果是:%d", p->data);
	Cut();

	printf("您想查值为几的元素位置?");
	scanf_s("%d", &e);
	int num = LocateElem(L, e);                      //查找:按值查找
	printf("查询结果是:%d", num);
	Cut();

	printf("在第几个位置插入?");
	scanf_s("%d",&i);
	printf("插入值的值是?");
	scanf_s("%d", &e);
	printf("插入结果如下:\n");
	if(ListAfterInsert(&L, i, e))                     //插入:后插
		Show(L);
	else
		printf("插入失败\n");
	Cut();

	printf("在第几个结点插入?");
	scanf_s("%d", &i);
	printf("插入值的值是?");
	scanf_s("%d", &e);
	printf("插入结果如下:\n");
	if (ListBeforeInsert(&L, i, e))                   //插入:前插
		Show(L);
	else
		printf("插入失败\n");
	Cut();
	
	printf("删除第几个位置的元素?");
	scanf_s("%d",&i);
	printf("删除结果如下:\n");
	if(ListOrderDelete(&L, i))                        //删除:按位删除
		Show(L);
	else
		printf("删除失败\n");
	Cut();

	printf("删除第几个结点的元素?");
	scanf_s("%d",&i);
	printf("删除结果如下:\n");
	if(ListNodeDelete(&L,i))                          //删除:指定结点删除
		Show(L);
	else
		printf("删除失败\n");
	Cut();

	getchar();
	return 0;
}

函数
可爱的分割线

void Cut()
{
    printf("\n=============== 完成 ===================\n");
}

初始化+判断表是否位空

/******************************************************************************/
//初始化:带头结点,头结点不存储数据
bool InitList(LinkList *L)
{
    (*L) = (LNode*)malloc(sizeof(LNode));
    //指向头结点
    if ((*L) == NULL)
        return false;//内存不足,分配失败

    (*L)->next = NULL;//头结点后暂时无其它结点
    return true;
}
/******************************************************************************/
//判断链表是否为空
bool Empty(LinkList L)
{
    if (L->next == NULL)
        return true;
    else
        return false;
}

创表:头插法(思路如图1)

/*----------------------------------------------------------------------------*/

//建表:头插法
LinkList HeadCreate(LinkList* L)
{
    //1,初始化链表
    (*L) = (LNode*)malloc(sizeof(LNode));
    (*L)->next = NULL;
    //2,定义头指针
    LNode* phead = (*L);

    int x;
    scanf_s("%d", &x);
    LNode* s;
    while (x != 999)//当输入为999时,不在增加链表长度
    {
        s = (LNode*)malloc(sizeof(LNode));
        s->data = x;
        s->next = phead->next;
        phead->next = s;
        scanf_s("%d", &x);
    }
    return (*L);
}

思路:
单链表 数据结构 C语言
(图1)

创表:尾插法(思路如图2)

/******************************************************************************/
//建表:尾插法
LinkList TailCreate(LinkList* L)
{
    //1,初始化LocateElem(LinkList L, int e);
    (*L) = (LNode*)malloc(sizeof(LNode));
    (*L)->next = NULL;

    //2,定义尾指针
    LNode* ptail = (*L);

    int x = 1;
    scanf_s("%d", &x);
    LNode* s;
    while (x != 999)//当输入为999时,不在增加链表长度
    {
        s = (LNode*)malloc(sizeof(LNode));
        s->data = x;
        ptail->next = s;
        ptail = s;
        scanf_s("%d", &x);
    }
    ptail->next = NULL;//最后一个元素指向空
    return (*L);          //把链表传回
}

思路:
单链表 数据结构 C语言
(图2)

打印单链表+求表长

/********************************************************************************/
//打印单链表
void Show(LinkList L)
{
    LNode* p = L->next;
    while (p != NULL)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}
/******************************************************************************/
//求链表长度
int Length(LinkList L)
{
    LNode* p = L;
    int length = 0;
    while (p != NULL)
    {
        p = p->next;
        length++;
    }
    return length;//算上了头结点
}

查找:按位查找+按值查找

/*-----------------------------------------------------------------------------*/
//按位查找:找到第i位的元素
LNode* GetElem(LinkList L, int i)
{
    if (i < 1)
        return false;
    LNode* p = L;
    int j = 0;
    while (p != NULL && j < i)
    {//找到第i个结点
        p = p->next;
        j++;
    }
    return p;
}
/******************************************************************************/
//按值查找,找到值位e对应的元素位置
int LocateElem(LinkList L, int e)
{
    LNode* p = L->next; //从第一个结点开始找
    int num = 1;
    while (p != NULL && p->data != e)
    {
        p = p->next;
        num++;
    }

    return num;
}

插入:后插(思路如图3)

/*------------------------------------------------------------------------------*/
//指定结点后插:在p节点后插入元素e
bool InsertNextNode(LNode* p, int e)
{
    if (p == NULL)
        return false;     //i不合法:第i-1个地址不存在
    LNode* s = (LNode*)malloc(sizeof(LNode)); //为新元素申请空间
    if (s == NULL)
        return false;     //内存malloc分配失败
    s->data = e;          //装data
    s->next = p->next;    //指向下一个元素地址
    p->next = s;          //新元素的地址给p
    return true;          //插入成功
}
/******************************************************************************/
//按位序插入:在第i个位置插入指定元素e
bool ListAfterInsert(LinkList* L, int i, int e)
{
    // 1,因为在第i个结点插入,所以需要找到第i-1个结点
    if (i < 1)
        return false; //传入的i不合法
    LNode* p;         //指针p记录当前位置
    p = (*L);            //p刚开始在表头
    int j = 0;        //当前p指向的是第几个结点,初始指向头,理解成第0个结点先
    while (p != NULL && j < i - 1)  //循环找到第i-1个结点
    {
        p = p->next;
        j++;
    }

    //2,插入
    return InsertNextNode(p, e);
}

思路:
单链表 数据结构 C语言
(图3)

插入:前插(思路如图4)

/******************************************************************************/
//指定结点前插:在p节点前插入元素e
bool InsertFormerNode(LNode* p, int e)
{
    LNode* s = (LNode*)malloc(sizeof(LNode));
    if (p == NULL || s == NULL)
        return false;   //i不合法或malloc内存分配失败
    s->next = p->next;
    p->next = s;        //在p后插入空间s
    s->data = p->data;  //前一个位置的值给后一个
    p->data = e;        //相当于前插入元素e
    return true;
}
/******************************************************************************/
//按位序插入:在第i个结点插入e(头结点为第一个结点)
bool ListBeforeInsert(LinkList* L, int i, int e)
{
    // 1,找到第i-1个结点
    if (i <= 1)
        return false; //传入的i不合法
    LNode* p;         //指针p记录当前位置
    p = (*L);            //p刚开始在表头
    int j = 0;        //当前p指向的是第几个结点,初始指向头,理解成第0个结点先
    while (p != NULL && j < i-1)  //循环找到第i-1个结点
    {
        p = p->next;
        j++;
    }

    //2,插入
    return InsertFormerNode(p, e);
}

思路:
单链表 数据结构 C语言
(图4)

删除:按位序删除(思路如图5)

/*-----------------------------------------------------------------------------*/
//按位序删除:删除第i个元素,并且用e返回删除元素的值
bool ListOrderDelete(LinkList* L, int i)
{
    //1,删除第i个元素,所以先找到第i-1个元素,以便断开连接
    if (i < 1)
        return false;
    LNode* p = (*L); //指针p记录当前位置;刚开始指向表头
    int j = 0;
    while (p != NULL && j < i - 1)
    {
        p = p->next;
        j++;
    }

    //2,删除并记录第i个元素
    if (p == NULL)
        return false;   //i不合法
    if (p->next == NULL)
        return false;   //i后无元素可删除
    LNode* q = p->next;
    p->next = q->next;
    int e;
    e = q->data;
    free(q);
    return true;
}

思路:
单链表 数据结构 C语言
(图5)

删除:指定结点删除(思路如图6)

/******************************************************************************/
//指定结点删除:删除p结点的元素
bool DeleteNode(LNode* p)
{
    if (p->next == NULL)
        return false;
    LNode* q = p->next;
    p->data = q->data;
    p->next = q->next;
    free(q);
    return true;
}//bug:p为最后一个节点时,删不了

/******************************************************************************/
//按结点删除:删除第i个结点的元素
bool ListNodeDelete(LinkList* L, int i)
{
    //1,删除第i个元素,所以先找到第i-1个元素,以便断开连接
    if (i < 1)
        return false;
    LNode* p = (*L); //指针p记录当前位置;刚开始指向表头
    int j = 0;
    while (p != NULL && j < i - 1)
    {
        p = p->next;
        j++;
    }

    //2,删除并记录第i个元素
    return DeleteNode(p);
}

思路:
单链表 数据结构 C语言
(图6)