数据结构入门-离散存储(链表)

一、预备知识:typedef

基本使用

#include <stdio.h>

typedef int AAA; // 为int再重新取一个名字,AAA就等于int

typedef struct Student
{
    int sid;
    char name[100];
    char sex;
}ST;

int main(void)
{

    int i = 10; // 等价于 AAA = 10; 

    struct Student st;  // 等价于  ST st;
    struct Student * ps = &st;  // 等价于 ST * ps = &st;

    ST st2;
    st2.sid = 10;

    printf("%d \n", st2.sid);

    return 0;
}

也可以这样使用,这样更加的方便

#include <stdio.h>

typedef struct Student
{
    int sid;
    char name[100];
    char sex;
}* PST;  // PST等价于 typedef struct * 

int main(void)
{
    struct Student st;
    PST ps = &st;

    ps->sid = 99;
    printf("%d\n", ps->sid);

    return 0;
}

还可以把上面的两个结合起来

#include <stdio.h>

typedef struct Student
{
    int sid;
    char name[100];
    char sex;
}* PST , STU;  // PST等价于 typedef struct *  , STU代表了typedef struct

int main(void)
{
    STU st;  // 等价于struct Student st
    PST ps = &st;

    ps->sid = 99;
    printf("%d\n", ps->sid);

    return 0;
}

二、离散存储(链表)

定义:n个节点离散分配,彼此通过指针相连,每一个节点只有一个前驱节点和一个后续节点,首节点没有前驱节点,尾节点没有后续节点

专业术语:

  1. 首节点:第一个有效节点
  2. 尾节点:最后一个有效节点
  3. 头节点:首节点前面
  4. 头指针:指向头节点的指针变量
  5. 尾指针:指向尾节点的指针变量

注意:头节点的数据类型和首节点类型一样,头节点里面没有存放有效数据,没有实际含义,为了方便对链表的操作

如果通过希望一个函数来对链表进行处理,我们至少需要接收链表的那些参数

只需要一个参数:头指针

因为我们可以通过头指针推算出链表的其他所有参数

每一个链表节点的数据类型如何表示

#include <stdio.h>

typedef struct Node
{
    int data;  // 数据域
    struct Node * pNext; // 指针域 指向了和它本身类型一样的另外一个节点
}NODE , *PNODE;
// NODE 等价于struct Node
// PNODE 等价于struct Node *

int main(void)
{
    return 0;
}

分类:

  1. 单链表
  2. 双链表:每一个节点有两个指针域
  3. 循环链表:能通任何一个节点找到其他所有的节点
  4. 非循环链表

算法:

  1. 遍历
  2. 查找
  3. 清空
  4. 销毁
  5. 求长度
  6. 排序
  7. 删除节点
  8. 插入节点

算法

狭义的算法是与数据的存储方式密切相关

广义的算法与数据的存储方式无关

泛型

利用某种技术达到的效果就是:不同的存储方式,执行的操作是一样的

多敲代码,熟练的掌握,并进行改进

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

typedef struct Node
{
    int data;
    struct Node * pNext;
}NODE , *PNODE;   // NODE等价于struct Node , PNODE等价于struct Node *

PNODE create_list(void);
void traverse_list(PNODE pHead);
bool is_empty(PNODE pHead);
int length_list(PNODE pHead);
bool insert_list(PNODE , int ,int); // 第二个是插入位置,第三个是插入的值
bool delete(PNODE , int, int*); // 第二个是删除的位置,第三个是所删除位置的值
void sort_list(PNODE pHead);

int main(void)
{
    PNODE pHead = NULL; // 等价于struct Node * pHead = NULL;

    pHead = create_list(); // 创建一个非循环单链表,并将该链表的头节点地址付给pHead

    // if(is_empty(pHead))
    //  printf("链表为空\n");
    // else
    //  printf("链表不为空\n");

    // printf("链表的长度为%d\n", length_list(pHead) );
    // sort_list(pHead);
    insert_list(pHead , 4, 99);

    int val;
    if(delete(pHead, 1 , &val))
    {
        printf("删除成功,你删除的是%d\n", val);
    }
    else
    {
        printf("删除失败\n");
    }

    traverse_list(pHead);

    return 0;
}

// 构建一个链表,并把头节点地址值返回
PNODE create_list(void)
{
    int len;
    int i;
    int val; // 用来临时存放用户输入的节点的值

    // 分配了一个不存放数据的头结点
    PNODE pHead = (PNODE)malloc(sizeof(NODE));
    if (pHead == NULL)
    {
        printf("分配失败,程序终止!\n");
        exit(-1);
    }

    // pTail始终执行的都是尾结点
    PNODE pTail = pHead;
    pTail->pNext = NULL;

    printf("请输入你需要生成的链表节点的个数:\n");
    scanf("%d" , &len);

    for (i = 0; i < len; ++i)
    {
        printf("请输入第%d个节点的值:", i+1);
        scanf("%d" , &val);

        PNODE pNew = (PNODE)malloc(sizeof(NODE));
        if (pNew == NULL)
        {
            printf("分配失败,程序终止!\n");
            exit(-1);
        }

        pNew->data = val;
        pTail->pNext = pNew;
        pNew->pNext = NULL;
        pTail = pNew;
    }

    return pHead;
}

// 进行遍历
void traverse_list(PNODE pHead)
{
    // 自定义一个指针用于遍历
    PNODE p = pHead->pNext;
    while(p != NULL){
        printf("%d ",p->data );
        p = p->pNext;
    }
    return;
}

// 判断链表是否为空
bool is_empty(PNODE pHead)
{
    if (pHead->pNext == NULL)
        return true;
    else
        return false;
}

// 链表的长度
int length_list(PNODE pHead)
{
    // 自定义一个指针用于计算链表的长度
    PNODE p = pHead->pNext;
    int len = 0;

    while(NULL != p)
    {
        ++len;
        p = p->pNext;
    }
    return len;
}

// 进行排序
void sort_list(PNODE pHead)
{
    // 这里和数组的排序差不多,思想是一样的

    int i , j , t;
    PNODE p , q;

    int len = length_list(pHead);

    for (i = 0 , p = pHead->pNext; i < len -1; ++i , p = p->pNext)
    {
        for (j = i+1 , q = p->pNext; j < len; ++j , q = q->pNext)
        {
            if (p->data > q->data)
            {
                t = p->data;
                p->data = q->data;
                q->data = t;
            }
        }
    }

    return;

}

// 插入操作
// 在pHead所指向链表的第pos个节点的前面插入一个新的结点,该结点的值是val,pos从1开始
bool insert_list(PNODE pHead, int pos , int val)
{

    int i = 0;
    PNODE p = pHead;

    while(NULL != p && i < pos-1)
    {
        p = p->pNext;
        ++i;
    }

    if (i > pos-1 || NULL == p)
        return false;

    PNODE pNew = (PNODE)malloc(sizeof(NODE));
    if (NULL == pNew)
    {
        printf("动态分配内存失败\n");
        exit(-1);
    }
    pNew->data = val;
    PNODE q = p->pNext;
    p->pNext = pNew;
    pNew->pNext = q;

    return true;
}

// 删除操作
bool delete(PNODE pHead , int pos, int * pval)
{

    int i = 0;
    PNODE p = pHead;

    while(NULL != p->pNext && i < pos-1)
    {
        p = p->pNext;
        ++i;
    }

    if (i > pos-1 || NULL == p->pNext)
        return false;

    PNODE q = p->pNext;
    *pval = q->data;

    // 删除p结点后面的结点
    p->pNext = p->pNext->pNext;
    free(q);
    q = NULL;

    return true;
}

原文地址:https://www.cnblogs.com/mengd/p/11973677.html

时间: 2024-07-30 10:06:48

数据结构入门-离散存储(链表)的相关文章

[转]算法与数据结构——入门总结与自学资料推荐

[转]算法与数据结构——入门总结与自学资料推荐 本文转自(http://www.cnblogs.com/jiahuix/p/4868881.html) 一.大纲 博客:董西城.Vamei 思维导图下载地址:http://pan.baidu.com/s/1gdCqW8r 二.数据结构资料推荐 数组:查找快O(1),插入删除慢O(n) 链表:查找慢O(n),插入删除快O(1) 块状链表:查找插入删除O(sqrt(n)):数组+链表: 队列:先进先出 堆栈:先进后出 双端队列:队列与堆栈结合,有hea

Java数据结构和算法之链表

三.链表 链结点 在链表中,每个数据项都被包含在'点"中,一个点是某个类的对象,这个类可认叫做LINK.因为一个链表中有许多类似的链结点,所以有必要用一个不同于链表的类来表达链结点.每个LINK对象中都包含一个对下一个点引用的字段(通常叫做next)但是本身的对象中有一个字段指向对第一个链结点的引用. 单链表 用一组地址任意的存储单元存放线性表中的数据元素. 以元素(数据元素的映象)  + 指针(指示后继元素存储位置)  = 结点(表示数据元素 或 数据元素的映象) 以"结点的序列&q

[考研系列之数据结构]线性表之链表

1.链表分类 通过线性表概述,我们知道了链表这样一种数据结构,它又分成三类,分别是 单向链表 循环链表 双向链表 单向链表 单向链表的指针域只有一个指向下一个节点的指针,需要注意几点: 1.头指针--指向第一个节点 2.最后一个结点的指针指向NULL 3.头结点--在链表的第一个结点之前附设一个结点,它的数据域为空 所以,我们看到:  单向链表为空的<=>链表有且只有一个头结点<=>头结点的指针指向NULL 循环链表 循环链表和单向链表最大的不同就是:最后一个结点的指针不再指向NU

【算法与数据结构】图 -- 十字链表

图的[十字链表]表示法是一种链式存储结构,可以看成是[邻接表]和[逆邻接表]的组合 本文中用到的有向图 /************************************************************************ 有向图的存储:十字链表 有向图的十字链表存储结构,是有一种链式存储结构,可以看成是[邻接表]和[逆邻接表] 的结合. 图中每条弧对应一个[弧结点],每个顶点对应一个[顶点结点] 弧结点 -------------------------------

记数据结构--入门和预备知识

数据结构(一)--入门和预备知识 1. 概述 数据结构定义: 我们如何把现实中大量而复杂的问题以特定的数据类型和特定的存储结构保存到主存储器(内存)中, 以及在此基础上为实现某个功能(如元素的CURD.排序等)而执行的相应操作,这个相应的操作也叫算法. 数据结构 = 元素的存储 + 元素的关系的存储算法 = 对数据存储的操作 算法: 算法就是:解决问题的方法和步骤 衡量算法有如下标准: 时间复杂度(程序要执行的次数,并非执行时间) 空间复杂度(算法执行过程中大概要占用的最大内存) 难易程度(可读

一 数据结构入门

基本概念 有哪些数据结构? 线性表,栈,队列,串,数组,广义表,树,二叉树,图 重点是线性表,二叉树 每种数据结构需要掌握,添加.更新.删除.查询.排序等操作的实现 学习数据结构的四种境界: 境界1:听懂理论,听懂算法思路 境界2:完成主要数据结构基本算法的实现(理论+实践,数据结构入门) 境界3:完成更多数据结构更多算法的实现 境界4:融会贯通,举一反三,在后续开发中综合应用数据结构知识. 数据(data): 是描述客观事物的数值.字符.以及能输入及其且能被处理的各种符号集合.例如:数值.字符

数据结构第一讲,数据结构入门了解知识.

目录 数据结构入门简介 一丶数据结构的四种分类 1.集合结构 2.线性结构 3.树结构 4.图结构 二丶物理结构简介 1.存储器 2.数据元素的存储形式 三丶总结 数据结构入门简介 一丶数据结构的四种分类 我们常听的一句话就是, 数据结构 + 算法 = 程序 意思就是在我们的程序设计中,数据结构是必不可少的,那么什么是数据结构,数据结构简而言之就是针对数据关系而生产的产物.可能不是很理解.因为我们程序编写过程中,程序中产生的数据怎么存储这都是数据关系. 常见的数据结构种类. 集合 线性结构 树结

自己动手实现java数据结构(二) 链表

1.链表介绍 前面我们已经介绍了向量,向量是基于数组进行数据存储的线性表.今天,要介绍的是线性表的另一种实现方式---链表. 链表和向量都是线性表,从使用者的角度上依然被视为一个线性的列表结构.但是,链表内部存储数据的方式却和向量大不相同:链表的核心是节点.节点存储"数据"的同时还维护着"关联节点的引用".要理解链表,首先必须理解链表的内部节点结构. 最简单的链表结构是单向链表,单向链表中的内部节点存储着数据(data)和其关联的下一个节点的引用(next). da

数据结构之_单链表的实现

数据结构之_单链表的实现 1.基本概念 链式存储定义 为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息. 单链表 线性表的链式存储结构中,每个节点中只包含一个指针域,这样的链表叫单链表. 通过每个节点的指针域将线性表的数据元素按其逻辑次序链接在一起(如图). 概念解释: 表头结点 链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息 数据结点 链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息