数据结构学习之单向链表[附Java实现代码]

来源:互联网 发布:mac os x 历史版本 编辑:程序博客网 时间:2024/05/21 07:07

个人博客
阅读原文
//开始挑战数据结构 ^_^

  • 什么是链表
    • 概念
      • 链表是一种物理存储单元上非连续/非顺序的存储结构.

    • 节点
      • 概念
        • 所谓链表即是由多个节点组成,像一条铁链,铁链的每一个环就相当于链表的节点.

      • 组成
        • 数据域
          • 一个节点用于储存数据的内存控件

        • 指针域
          • 一个节点用于储存和它连接的下一个节点地址的内存空间



    • 优点
      • 创建节点
        • 不需要指定内存空间的大小,非常具有灵活性

      • 删除节点
        • 删除一个节点不需要像数组那样将其余的数据整体向前移动,只需要修改节点的指针域即可完成删除节点的操作


      • 缺点
        • 访问节点
          • 可以通过循环或者递归访问到链表的任何数据,但是访问效率低于数组(线性数据结构)

        • 储存方面
          • 由于不是线性结构,并且相对于线性的储存结构来说,需要保存每个节点的指针域,这又是一笔内存开销,占用了内存空间,对内存空间的利用效率低




  • 链表的种类
    • 方向
      • 单向链表
        • 是连接方向单一的链表,从头结点开始可以一直指向尾节点,方向不会改变(即从头结点走到尾节点只有一条路径).其中每一个节点的指针域只有一个指向,也就是一个节点有一个指针,可以保存下一个节点

      • 双向链表
        • 每一个节点的指针域中保存有两个指针(引用),可以同时指向该节点的前驱节点和后继节点


    • 形状
      • 单链表
        • 单链表:是一种逻辑上的线性结构,只有一条链,首尾不相接

      • 环形链表
        • 环形链表:首尾相接的链表(类比丢手帕)(约瑟夫问题)



  • 如何创建链表
    • 思路分析
      • 图形化结构
        • 链表signal-linked-listsignal-circular-linked-listdouble-signal-linked-listdouble-signal-circular-linked-list
        • 节点
          • 节点类图Node-class
          • 节点属性
            • 数据域 : 节点中储存数据内存控件
            • 指针域 : 节点中储存其他节点(可能是下一个,也可能是上一个)的地址信息的内存空间


        • 类图
          • [Java]链表类图LinkedList_Class_Map


      • 文本思路
        • 单向链表
        • 双向链表
        • 单向环形链表
        • 双向环形链表


    • 代码实现
      • C
      • Java代码


  • 如何使用链表
    • 节点
      • 属性
        • 数据域 : Object data
        • 指针域 : Node nextNode

      • 方法
        • 查询节点数据 : private Object getData()
        • 修改节点数据 : private void setData(Object newData)


    • 链表
      • 属性
        • 长度 : int length = 0
        • 头结点引用 : Node firstNode = null
        • 前驱节点引用 : Node lastNode = null
        • 临时节点引用 : Node point = null

      • 方法
        • 初始化链表(利用构造器) : public LinkedList()
        • 增加尾节点 : public void add()
        • 插入指定节点 : public void insert(int index)
        • 删除尾节点 : public void del()
        • 删除指定节点 : public void del(int index)
        • 修改尾节点 : public void update(Object newData)
        • 修改指定节点 : public void update(int index, Object newData)
        • 获取尾节点 : public Node getNode()
        • 获取指定节点 : public Node getNode(int index)
        • 链表长度 : public int length()
        • 判断空链表 : public boolean isEmpty()
        • 排序 : public void sort()
        • 截取链表 : public LinkedList subLinkedList(int start, int end)



  • 如何优化链表
    • 算法方面
      • 排序算法
        • 冒泡排序
        • 选择排序
        • 插入排序

      • 检索算法

    • 操作方法
    • 待续

package linkedList;/** * 节点类(单向链表) * @author 王一航 */class Node {    //数据域    Object data;    //指针域    Node nextNode = null;//单向链表因此只有一个指向自身类型的引用    //构造函数    public Node(Object data){        this.data = data;    }}
package linkedList;/** * 单向链表类 * @author 王一航 */public class LinkedList {    /**     * 成员变量     */    int length = 0;    Node firstNode = null;    Node lastNode = null;    Node point = null;    /**     * 成员方法     */    //初始化链表(利用构造器)    public LinkedList(){        int length = 0;        Node firstNode = null;        Node lastNode = null;        Node point = null;    }    //增加尾节点    public void add(Object data){        insert(length, data);    }    //插入指定节点    public void insert(int index, Object data){        Node temp = getNode(index);        Node node = new Node(data);        if(index > 0){            getNode(index - 1).nextNode = node;         }else{            firstNode = node;        }        node.nextNode = temp;        length++;    }    //删除尾节点    public void del(){        del(length - 1);    }    //删除指定节点    public void del(int index){        //TODO 检查入口参数        if(index > 0){            getNode(index - 1).nextNode = getNode(index + 1);            length--;        }        if(index == 0){            firstNode = getNode(1);            length--;        }    }    //修改尾节点    public void update(Object newData){        update(length - 1, newData);    }    //修改指定节点    public void update(int index, Object newData){        getNode(index).data = newData;    }    //获取尾节点    public Node getNode(){        return getNode(length - 1);    }    //获取指定节点    public Node getNode(int index){        try{            point = firstNode;            int count = 0;            while(count < index){                point = point.nextNode;                count++;            }            return point;        }catch(NullPointerException e){            System.out.println("请检查链表是否越界! 链表长度 : " + length);            return null;        }    }    //链表长度    public int length(){        return length;    }    //判断空链表    public boolean isEmpty(){        return length == 0 ? true : false;    }    //排序    public void sort(){        //TODO 完成排序功能        System.out.println("请完成排序功能!");    }    //截取链表    public LinkedList subLinkedList(int start, int end){        if(end >= start){            firstNode = getNode(start);            getNode(end - start).nextNode = null;            length = end - start;        }        return this;        //TODO 释放不需要的内存    }    //打印链表所有元素    public void show(){        for(int i = 0; i < length; i++){            System.out.println("索引 : " + i + " 第" + (i+1) + "个" + getNode(i).data);        }    }}

经验总结(个人理解):

关于健壮性 :

当某一个方法需要入口参数的时候,必须对入口参数的合法性进行检查(以后要将这种意识变成一种意识)

关于代码结构 :

关于方法的组织 :

良好的代码中方法的组织结构应该具有”高内聚低耦合”的特点

高内聚 :

低耦合 :

关于属性和方法的命名 :

关于类图的使用 :

注意 :

1 . 杜绝魔术数字的出现,程序中一旦需要使用到某些常量,则必须首先声明常量为一个有意义的名字,然后根据这个名字去访问该常量

 

0 0
原创粉丝点击