数据结构与算法_链表1_单链表

链表可能是继数组之后第二种使用最为广泛的数据结构。

链表有单链表、双端链表、有序链表、双向链表。本文讲的就是链表中的基本即单链表,来了解链表的基本操作和概念。


通过下图简单了解链表的概念



其特点举个简单例子,如图把33这个元素插入在42之前,数组实现的话要把42开始之后为元素全部后移一位,然后把33插到指定位置,然而链表则可以随便的把他分配在某一个位置,然后我们通过修改指针关系,把散落在各个位置的单元串联起来,把原来指向42的指针指向33,并把33的下一个指针指向42仅仅这2步动作就完成了把33这个新单元加入到我们的链表中,并且后面这些元素7 98等根本没有感受到这个插入动作,对他们没有任何影响。

这样内存的分配比较灵活,可以随意的分配。


删除的时候同理。要把33这个单元删除,只要把指向它的那个指针再指向42就可以了,其他的什么都不需要动,注意此时的33单元没有任何指针指向它,现在它变成了垃圾对象,将来会被系统回收。然而单链表的随机访问很慢,要从head找到第一个元素然后找找找。。

还有两个概念即链结点和链表类;

上图中的每一项都是链结点,一个链结点是某个类的对象,这个类可以叫做Link。因为一个链表中有许多类似的链结点,所以有必要用一个不同于链表的类来表达链结点。每个Link对象中都包含一个对下一个链结点引用的字段(通常叫做next),但是链表本身的对象中有一个字段指向对第一个链结点的引用。

链表:LinkList类中只包含一个数据项:即对链表中第一个链结点的引用,叫做head。他是唯一的链表需要维护的永久信息,用以定位所有其他的链结点。从head出发,沿着链表通过每个链结点的next字段,就可以找到其他的链结点。


实现的代码如下:

public class YezhuLinkedList {
    public Link head = null;

    public boolean isEmpty() {
        return head == null;
    }

    /**
     * insertFirst() 作用是在表头插入一个新链结点。实际上,这是最容
     * 易插入的一个链结点。具体操作时,新创建的链结点的next指向原来
     * head指向的值,然后head指向新插入的链结点。
     */
    public void insertFirst(int a) {
        Link link = new Link(a);
        link.next = head; //新插入的元素 指向原来head指向的链接点
        head = link;//head指向新插入的元素
    }

    /**
     * 展示全部的结点数据
     */
    public void showAll() {
        //从head开始遍历 到最后一个元素的时候 指向的肯定是空
        Link current = head;
        while (current != null) {
            System.out.println(current.data);
            current = current.next;
        }
    }

    /**
     * 在尾部插入元素
     * 从头开始一直遍历 遍历到尾部 让之前Link的next指向新的结点
     */
    public void insertLast(int data) {
        Link link = new Link(data);

        if (head == null) {
            link.next = head;
            head = link;
        } else {

            Link current = head;
            while (current.next != null) {
                current = current.next;
            }

            current.next = link;
        }


    }

    /**
     * 删除头元素
     */
    public void deleteFirst() {
        Link current = head;
        head = current.next;
    }

    /**
     * 长度
     *
     * @return
     */
    public int length() {
        int length = 0;
        Link link = head;
        while (link != null) {
            length++;
            link = link.next;
        }
        return length;
    }

    /**
     * 根据元素的关键字 找到其结点所在的位置
     *
     * @param data
     * @return
     */
    public int getPosByValue(int data) {
        Link current = head;
        int position = 0;

        if (!contains(data)) {
            return -1;
        } else {
            while (current.data != data) {

                position++;
                if (current.next == null) {
                    return position;
                } else {
                    current = current.next;
                }
            }
            return position;
        }
    }

    /**
     * 整个链表中是否包含关键字为data的链结点
     *
     * @param data
     * @return
     */
    public boolean contains(int data) {
        Link current = head;
        int position = 0;
        while (current.data != data && current.next != null) {
            //判断条件加上current.next != null 是为了队尾的时候的空指针
            position++;
            current = current.next;
        }

        //遍历到链表的尾部 要是position到了尾部 说明没有包含此元素
        if (position == length() - 1) {
            return false;
        } else {
            return true;
        }
    }

}
 测试代码:

/**
 * 测试
 */

public class Test {
    public static void main(String[] args) {
        YezhuLinkedList yezhuLinkedList = new YezhuLinkedList();

        yezhuLinkedList.insertFirst(1);
        yezhuLinkedList.insertFirst(5);

        yezhuLinkedList.insertLast(8);

        yezhuLinkedList.insertFirst(3);

        yezhuLinkedList.showAll();

        //测试是否包含关键字是data的链结点,有则输出位置
        int data = 10;
        if (yezhuLinkedList.contains(data)) {
            System.out.println("包含此元素,在链表中的位置是:" + yezhuLinkedList.getPosByValue(data));
        } else {
            System.out.println("不包含此元素");
        }

//        yezhuLinkedList.deleteFirst();
        System.out.println("链表长度是" + yezhuLinkedList.length());
    }
}

输出结果:



其过程中我们可以看到一个这样的结构,能更清楚的了解链表的属性结构:


显然就是从head链结点一个指向一个的展开。


如上代码如有问题请多多指出。


关于链结点补充:

1.链结点中的数据域可能包含很多的数据项,比如一个个人记录可能有姓名、地址、社保号、头衔等许多字段。通常用一个包含这些数据的类的对象来代替这些数据项。

2.可以让每个链表的链结点是一个小型的数组,比如我们一个数组要表达十万个这样的数据,我们可以把每一百或一千个这样的数组做成一个小单元,把这样的小单元用链表串

联起来,那么它既有数组的结构又有链表的优点,也就是数据结构灵活的综合的应用。

也就是说真实的链表在实际使用过程中有很多的变种,一定要灵活的选择合适的机构。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值