01-(2)数据结构- 一步一步写算法(之单向链表)

 有的时候,处于内存中的数据并不是连续的。那么这时候,我们就需要在数据结构中添加一个属性,这个属性会记录下面一个数据的地址。有了这个地址之后,所有的数据就像一条链子一样串起来了,那么这个地址属性就起到了穿线连结的作用。
    相比较普通的线性结构,链表结构的优势是什么呢?我们可以总结一下:
    (1)单个节点创建非常方便,普通的线性内存通常在创建的时候就需要设定数据的大小
    (2)节点的删除非常方便,不需要像线性结构那样移动剩下的数据
    (3)节点的访问方便,可以通过循环或者递归的方法访问到任意数据,但是平均的访问效率低于线性表
    那么在实际应用中,链表是怎么设计的呢?我们可以以int数据类型作为基础,设计一个简单的int链表:
  1)设计链表的数据结构
[cpp] view plain copy
typedef struct _LINK_NODE
{
    int data;
    struct _LINK_NODE* next;
}LINK_NODE;  

    2)创建链表
[cpp] view plain copy
LINK_NODE* alloca_node(int value)
{
    LINK_NODE* pLinkNode = NULL;
    pLinkNode = (LINK_NODE*)malloc(sizeof(LINK_NODE));  

    pLinkNode->data = value;
    pLinkNode->next = NULL;
    return pLinkNode;
}
  3)删除链表
[cpp] view plain copy
void delete_node(LINK_NODE** pNode)
{
    LINK_NODE** pNext;
    if(NULL == pNode || NULL == *pNode)
        return ;  

    pNext = &(*pNode)->next;
    free(*pNode);
    delete_node(pNext);
}
    4)链表插入数据
[cpp] view plain copy
STATUS _add_data(LINK_NODE** pNode, LINK_NODE* pDataNode)
{
    if(NULL == *pNode){
        *pNode = pDataNode;
        return TRUE;
    }  

    return _add_data(&(*pNode)->next, pDataNode);
}  

STATUS add_data(const LINK_NODE** pNode, int value)
{
    LINK_NODE* pDataNode;
    if(NULL == *pNode)
        return FALSE;  

    pDataNode = alloca_node(value);
    assert(NULL != pDataNode);
    return _add_data((LINK_NODE**)pNode, pDataNode);
}
    5)删除数据
[cpp] view plain copy
STATUS _delete_data(LINK_NODE** pNode, int value)
{
    LINK_NODE* pLinkNode;
    if(NULL == (*pNode)->next)
        return FALSE;  

    pLinkNode = (*pNode)->next;
    if(value == pLinkNode->data){
        (*pNode)->next = pLinkNode->next;
        free(pLinkNode);
        return TRUE;
    }else{
        return _delete_data(&(*pNode)->next, value);
    }
}  

STATUS delete_data(LINK_NODE** pNode, int value)
{
    LINK_NODE* pLinkNode;
    if(NULL == pNode || NULL == *pNode)
        return FALSE;  

    if(value == (*pNode)->data){
        pLinkNode = *pNode;
        *pNode = pLinkNode->next;
        free(pLinkNode);
        return TRUE;
    }         

    return _delete_data(pNode, value);
}
    6)查找数据
[cpp] view plain copy
LINK_NODE* find_data(const LINK_NODE* pLinkNode, int value)
{
    if(NULL == pLinkNode)
        return NULL;  

    if(value == pLinkNode->data)
        return (LINK_NODE*)pLinkNode;  

    return find_data(pLinkNode->next, value);
}
    7)打印数据
[cpp] view plain copy
void print_node(const LINK_NODE* pLinkNode)
{
    if(pLinkNode){
        printf("%d\n", pLinkNode->data);
        print_node(pLinkNode->next);
    }
}
    8)统计数据
[cpp] view plain copy
int count_node(const LINK_NODE* pLinkNode)
{
    if(NULL == pLinkNode)
        return 0;  

    return 1 + count_node(pLinkNode->next);
}  
时间: 2024-07-31 18:50:11

01-(2)数据结构- 一步一步写算法(之单向链表)的相关文章

一步一步写算法(之链表排序)

原文:一步一步写算法(之链表排序) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 相比较线性表的排序而言,链表排序的内容稍微麻烦一点.一方面,你要考虑数据插入的步骤:另外一方面你也要对指针有所顾虑.要是有一步的内容错了,那么操作系统会马上给你弹出一个exception.就链表的特殊性而言,适合于链表的排序有哪些呢? (1)插入排序    (适合) (2)冒泡排序    (适合) (3)希尔排序    (适合) (4)选择排序    (适

一步一步写算法(之链表逆转)

原文:一步一步写算法(之链表逆转) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 链表逆转是面试环境中经常遇到的一道题目,也是我们在实际开发中可能会遇到的开发需求.和线性逆转不一样,单向链表的节点需要一个一个进行处理.为了显示两者之间的区别,我们分别对线性内存和链表进行逆转: (1)普通连续内存数据的反转分析 STATUS normal_revert(int array[], int length) { int* pData ; int

一步一步写算法(之链表重合)

原文:一步一步写算法(之链表重合) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 链表重合是一个好玩的问题.原题目是这样的:有两个链表,那么如何判断这两个链表是不是重合的?至于这个链表在什么时候重合的,这不重要,关键是判断这个链表究竟有没有重合.究竟有什么方法呢? 最简单的方法就是查看两者有没有共同点.那么依次判断就行了. int find_node_in_link(LINK_NODE* pLink, LINK_NODE* pNode)

数据结构和算法之单向链表二:获取倒数第K个节点

我们在做算法的时候或多或少都会遇到这样的问题,那就是我们需要获取某一个数据集的倒数或者正数第几个数据.那么今天我们来看一下这个问题,怎么去获取倒数第K个节点.我们拿到这个问题的时候自然而然会想到我们让链表从末尾开始next   K-1 次不就是第K-1个节点了么,但是必须要注意一点,这是单向链表.那么这时候的解决思路或许就会出现分歧,大多数人都会想到我们遍历一下链表,获取链表的长度,然后再减去 K 长度的节点,那么我们这个链表的最后一个节点就是原链表的倒数第K个节点:我们看一下实现代码: /**

数据结构和算法之单向链表六:链表的反转以及链表节点的删除

在前面介绍了关于链表的一系列问题,这里我们在介绍一下关于单向链表的反转这个比较具有代表性的算法.在进行反转的时候一定要记住多画图,多去理解在链表进行反转的时候它对于地址的改变,这和数组的数据对换具有很大的不一致. public Node reverseList(Node head){ //判断链表是否为空或者只有一个节点 if(head == null || head.next == null){ return head; } //准备三个节点 Node next = null;//保存当前节点

数据结构与算法(三)--单向链表

有的时候,处于内存中的数据并不是连续的.那么这时候,我们就需要在数据结构中添加一个属性,这个属性会记录下面一个数据的地址.有了这个地址之后,所有的数据就像一条链子一样串起来了,那么这个地址属性就起到了穿线连结的作用. 相比较普通的线性结构,链表结构的优势是什么呢?我们可以总结一下: (1)单个节点创建非常方便,普通的线性内存通常在创建的时候就需要设定数据的大小 (2)节点的删除非常方便,不需要像线性结构那样移动剩下的数据 (3)节点的访问方便,可以通过循环或者递归的方法访问到任意数据,但是平均的

数据结构与算法学习-单向链表的实现

链表(Chain本文所说链表均为单向链表,以下均简称单向链表)实际上是由节点(Node)组成的,一个链表拥有不定数量的节点.而向外暴露的只有一个头节点(Head),我们对链表的所有操作,都是直接或者间接地通过其头节点来进行的. 节点(Node)是由一个需要储存的对象及对下一个节点的引用组成的.也就是说,节点拥有两个成员:储存的对象.对下一个节点的引用. 这样说可能大家不是很明白,我贴一张图大家可能更容易理解. package LinkedList; /** * <p><strong>

一步一步写算法(之通用数据结构)

原文:一步一步写算法(之通用数据结构) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 上一篇博客介绍了通用算法,那么有了这个基础我们可以继续分析通用数据结构了.我们知道在c++里面,既有数据又有函数,所以一个class就能干很多事情.举一个简单的例子来说,我们可以编写一个数据的class计算类. class calculate{ int m; int n; public: calculate():m(0),n(0) {} calcula

01-(2)数据结构- 一步一步写算法(之双向链表)

前面的博客我们介绍了单向链表.那么我们今天介绍的双向链表,顾名思义,就是数据本身具备了左边和右边的双向指针.双向链表相比较单向链表,主要有下面几个特点: (1)在数据结构中具有双向指针 (2)插入数据的时候需要考虑前后的方向的操作 (3)同样,删除数据的是有也需要考虑前后方向的操作 那么,一个非循环的双向链表操作应该是怎么样的呢?我们可以自己尝试一下: (1)定义双向链表的基本结构 [cpp] view plain copy typedef struct _DOUBLE_LINK_NODE {

一步一步写算法(之哈夫曼树 上)

原文:一步一步写算法(之哈夫曼树 上) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在数据传输的过程当中,我们总是希望用尽可能少的带宽传输更多的数据,哈夫曼就是其中的一种较少带宽传输的方法.哈夫曼的基本思想不复杂,那就是对于出现频率高的数据用短字节表示,对于频率比较低得数据用长字节表示. 比如说,现在有4个数据需要传输,分别为A.B.C.D,所以一般来说,如果此时没有考虑四个数据出现的概率,那么我们完全可以这么分配,平均长度为2, /