数据结构-无头 单向 非循环 链表函数接口实现

 
 

1. 单向、不带头、不循环链表介绍

在这里插入图片描述无头单向非循环链表:结构简单,但是实现接口时比较繁琐,一般不会用来单独存储数据,大部分作为其他结构的子结构应用。
 

2. 单链表结构体、常用函数接口

// 单向 不带头 不循环
typedef int SLTDataType;

typedef struct SListNode // 单链表的一个结点
{
    SLTDataType _data;
    struct SListNode* _next;
}SListNode;

typedef struct SList  // 单链表
{
    SListNode* _head; // 头指针
}SList;

   定义了两个结构体,第一个结构体是单链表的结点(数据域指针域),第二个结构体定义了指向单链表头指针
 
单链表的函数接口:

void SListInit(SList* plt); // 初始化
void SListPushBack(SList* plt, SLTDataType x);// 尾插
void SListPushFront(SList* plt, SLTDataType x);// 头插
void SListPopBack(SList* plt);// 尾删
void SListPopFront(SList* plt);// 头删

SListNode* SlistFind(SList* plt, SLTDataType x);// 寻找某个指定结点
void SListInsertAfter(SListNode* pos, SLTDataType x);// 指定位置后面添加
void SListEraseAfter(SListNode* pos);// 指定位置后面删除
void SListRemove(SList* plt, SLTDataType x);// 已知值的第一个结点删除
void SListRemoveAll(SList* plt, SLTDataType x);// 已知值的所有结点删除

void SListPrint(SList* plt);// 打印
void SListDestory(SList* plt);// 清空

 

3. 单链表接口的实现

3.1 初始化

初始化时,链表中没有结点,所有把头指针置空。

void SListInit(SList* plt) // 初始化
{
    assert(plt);
    plt->_head = NULL;
}

 

3.2 尾插

尾插一个新结点,先malloc一个新结点,再找到单链表最后一个结点,让最后一个结点的指针域指向新结点,最后新结点的指针置空。

void SListPushBack(SList* plt, SLTDataType x) // 尾插
{
    assert(plt);

    SListNode* newnode = (SListNode*)malloc(sizeof(SListNode)); // 申请一个新结点  
    newnode->_data = x;
    newnode->_next = NULL;
    // 1.空
    // 2.非空
    if (plt->_head == NULL)
    {
        plt->_head = newnode;
    }
    else
    {
        SListNode* cur = plt->_head;
        while (cur->_next != NULL)
        {
            cur = cur->_next;
        } // 找到尾结点  
        cur->_next = newnode;
    }
}

 

3.3 头插

头插一个新结点,先malloc一个新结点,将新结点的指针指向第二个结点,然后将头指针指向新的头结点。(这里不能把这两个步骤颠倒,如果先将头指针指向新结点的话,会丢失指向第二个结点的指针,当然你也可以提前定义一个新指针,保存这个指向第二个结点的指针,这就没必要了)。

void SListPushFront(SList* plt, SLTDataType x)// 头插
{
    assert(plt);

    SListnewnode = (SListNode*)malloc(sizeof(SListNode)); // 申请新结点   
    newnode->_data = x;
    newnode->_next = NULL;

    newnode->_next = plt->_head;
    plt->_head = newnode;
}

 

3.4 尾删

定义两个指向结点的指针,一前一后找到最后一个元素,n1指向倒数第二个结点,n2指向最后一个结点,释放掉n2,记得要把n2置空,防止野指针。再把n1的指针域置空。

void SListPopBack(SList* plt) // 尾删
{
    assert(plt);

    if (plt->_head == NULL)
    {
        printf("链表为空!\n");
        return;
    }
    else
    {
        SListNode* n1 = plt->_head;
        SListNode* n2 = plt->_head;
        while (n2->_next != NULL)
        {
            n1 = n2;
            n2 = n2->_next;
        }// 找到了最后一个结点  
        free(n2);
        n2 = NULL; // 置空
        n1->_next = NULL;
    }
}

 

3.5 头删

定义一个指向头结点的指针cur,再将指向第二个结点的指针(cur->_next)给头指针,释放掉cur指向的头结点,最后将cur置空。

void SListPopFront(SList* plt) // 头删
{
    assert(plt);

    if (plt->_head == NULL)
    {
        printf("链表为空!\n");
        return;
    }
    else
    {
        SListNode* cur = plt->_head;
        plt->_head = cur->_next;
        free(cur);
        cur = NULL;// 防止野指针
    }
}

 

3.6 寻找指定结点

定义一个指针cur,遍历单链表,依次比较,如果cur的值等于给定值,返回指针cur。

SListNode* SlistFind(SList* plt, SLDataType x) // 寻找某个指定结点  
{
    assert(plt);

    if (plt->_head == NULL)
    {
        printf("链表为空!\n");
        return;
    }
    else
    {
        SListNode* cur = plt->_head;
        while (cur != NULL)
        {
            if (cur->_data == x)
            {
                return cur; // 找到并返回  
            }
            else
            {
                cur = cur->_next;
            }
        }
        return NULL;
    }
}

 

3.7 指定位置后添加

已知pos指针,直接在其后面添加,让新结点指针指向pos的下一个结点,pos结点的指针指向新结点(这两个步骤不能颠倒)。

void SListInsertAfter(SListNode* pos, SLTDataType x)// 指定位置后面添加  
{
    assert(pos);

    SListNode* newnode = (SListNode*)malloc(sizeof(SListNode)); // 申请新结点  
    newnode->_data = x;
    newnode->_next = NULL;

    newnode->_next = pos->_next;
    pos->_next = newnode;
}

 

3.8 指定位置后删除

定义一个apos指针指向pos后面的结点,让pos的指针指向apos的下一个结点,此时可以安全释放掉apos指向的结点,最后将apos置空。

void SListEraseAfter(SListNode* pos)// 指定位置后面删除  
{
    assert(pos);

    if (pos->_next == NULL)
    {
        return;
    }
    else
    {
        SListNode* apos = pos->_next;
        pos->_next = apos->_next;
        free(apos);
        apos = NULL;

        //下面这种方法是错误的,因为pos->_next->_next可能指向非法地址。
        //pos->_next = pos->_next->_next;
        //free(pos->_next);
    }
}

 

3.9 删除第一个指定值结点

定义两个指针fcur和cur,一前一后,cur找指定值,找到后让fcur的_next指针指向cur的下一个结点,释放掉cur,cur置空。(注意各种边界条件!)

void SListRemove(SList* plt, SLTDataType x)// 已知值的第一个结点删除  
{
    assert(plt);

    if (plt->_head == NULL)
    {
        printf("链表为空!\n");
        return;
    }
    else
    {
        SListNode* fcur = NULL;
        SListNode* cur = plt->_head;
        while (cur != NULL)
        {
            if (cur->_data != x)
            {
                fcur = cur;
                cur = cur->_next;
            }
            else
            {
                if (fcur == NULL)
                    plt->_head = cur->_next;
                else
                    fcur->_next = cur->_next;
                free(cur);
                cur = NULL;
                return;
            }
        }
    }
}

 

3.10 删除指定值所有结点

定义两个指针prev和cur,一前一后,用循环控制多次删除,删除的方式同上,往后遍历依次比较(注意各种边界条件!)。

void SListRemoveAll(SList* plt, SLTDataType x)// 已知值的所有结点删除  
{
    assert(plt);

    if (plt->_head == NULL)
    {
        printf("链表为空!\n");
        return;
    }
    else
    {
        SListNode* prev = NULL;
        SListNode* cur = plt->_head;
        while (cur != NULL)
        {
            if (cur->_data == x)
            {
                if (prev == NULL)
                {  
                    SListNode* next = cur->_next;
                    plt->_head = next;
                    free(cur);
                    cur = next;
                }
                else // prev!=NULL
                {
                    SListNode* next = cur->_next;
                    prev->_next = next;
                    free(cur);
                    cur = next;
                }
            }
            else
            {
                prev = cur;
                cur = cur->_next;
            }
        }
    }
}

 

3.11 清空

定义cur指针,逐个遍历,逐个结点释放,最后释放置空。

void SListDestory(SList* plt) // 清空
{
    assert(plt);

    if (plt->_head == NULL)
    {
        printf("链表为空!\n");
        return;
    }
    else
    {
        SListNode* cur = plt->_head;
        while (cur != NULL)
        {
            SListNode* next = cur->_next;
            plt->_head = next;
            free(cur);
            cur = next;// 防止野指针
        }
    }
}

 

3.12 打印

定义cur指针,逐个遍历,依次打印。

void SListPrint(SList* plt) // 打印
{
    assert(plt);

    SListNode* cur = plt->_head;
    while (cur != NULL)
    {
        printf("%d->", cur->_data);
        cur = cur->_next;
    }
    printf("NULL\n");
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值