数据结构——链表(分别用Java与C#进行实现)

数据结构——链表

1.什么是链表?

  • 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的。
  • 每一个链表都包含多个节点,节点又包含两个部分,一个是数据域(储存节点含有的信息),一个是引用域(储存下一个节点或者上一个节点的地址)。
  • 链表的理解示意图:
    在这里插入图片描述

2.链表的特点

  • 获取数据麻烦,需要遍历查找,比数组慢
  • 方便插入、删除

因此,链表适用于频繁插入和删除数据的场景。

3.链表的实现原理

  1. 创建一个节点类,其中节点类包含两个部分,第一个是数据域(你到时候要往节点里面储存的信息),第二个是引用域(相当于指针,单向链表有一个指针,指向下一个节点;双向链表有两个指针,分别指向下一个和上一个节点)
  2. 创建一个链表类,其中链表类包含三个属性:头结点、尾节点和大小,方法包含添加、删除、插入等等方法。

基于面向对象的思想,分别利用Java和C#两种语言实现了单向链表和双向链表。

单向链表

基于Java实现的单向链表

节点类:

class Node{
    private Object element;
    private Object next;

    public Node() {
    }

    public Node(Object element) {
        this.element = element;
    }

    public Object getElement() {
        return element;
    }

    public void setElement(Object element) {
        this.element = element;
    }

    public Object getNext() {
        return next;
    }

    public void setNext(Object next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "Node{" +
                "element=" + element +
                ", next=" + next +
                '}';
    }
}

单向链表类:

public class MyLinkedList {
    private int length;
    private Object head;


    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public Object getHead() {
        return head;
    }

    public void setHead(Object head) {
        this.head = head;
    }


    // 添加一个元素
    public void append(Object element) {
        Node node = new Node(element);
        if(this.head == null) {
            this.head = node;
        }else {
            Node current = (Node) this.head;
            while (current.getNext() != null) {
                current = (Node) current.getNext();
            }
            current.setNext(node);
        }
        this.length++;
    }

    // 向指定位置插入一个元素
    public boolean insert(int position,Object element) {
        Node node = new Node(element);
        if (position < 0 || position > this.length){
            System.err.println("数组下标越界");
            return false;
        }
        if(position == 0) {
            Node first = (Node) this.head;
            this.head = node;
            node.setNext(first);
        }else{
            Node current = (Node) this.head;
            Node pre = null;
            int index = 0;
            while(index++ < position) {
                pre = current;
                current = (Node) current.getNext();
            }
            pre.setNext(node);
            node.setNext(current);
        }
        this.length++;
        return true;
    }

    // 获取对应位置的元素
    public Object get(int position) {
        if(position < 0 || position > this.length) {
           return null;
        }
        int index = 0;
        Node current = (Node) this.head;
        while (index++ < position) {
            current = (Node) current.getNext();
        }
        return current == null ? null : current.getElement();
    }

    // 返回元素在列表中的索引,如果没有就返回-1
    public int indexOf(Object element) {
        Node current = (Node) this.head;
        int index = 0;
        while(current.getNext() != null) {
            if(current.getElement().equals(element)) {
                return index;
            }
            index++;
            current = (Node) current.getNext();
        }
        if(current.getNext() == null) {
            current.getElement().equals(element);
            return this.length - 1;
        }

        return -1;
    }

    // 删除某个位置的元素
    public Object removeAt(int position) {

        if (position < 0 || position > this.length - 1) {
            System.err.println("下标越界");
            return null;
        }

        if(position == 0) {
            Node node = (Node) this.head;
            this.head = (Node) node.getNext();
            this.length--;
            return node.getElement();
        }
        Node current = (Node)this.head;
        Node pre = null;
        for (int i = 0; i < position; i++) {
            pre = current;
            current = (Node) current.getNext();
        }
        pre.setNext((Node) current.getNext());
        this.length--;
        return current.getElement();
    }

    // 修改某个位置的元素
    public boolean update(int position,Object newElement) {
        // 删除position位置的元素
        Object result = this.removeAt(position);
        // 在position出插入元素
        return result != null? this.insert(position,newElement):false;
    }
    // 删除指定的元素
    public int remove(Object element){
        int index = this.indexOf(element);
        if(index == -1){
            System.err.println(element + "不在链表中");
        }else{
            this.removeAt(index);
        }
        return index;
    }

    // 判断链表是否为空
    public boolean isEmpty(){
        return this.length <= 0;
    }

    // 获取链表的元素个数
    public int size(){
        return this.length;
    }

    @Override
    public String toString() {
        return "MyLinkedList{" +
                "length=" + length +
                ", head=" + head +
                '}';
    }

    public static void main(String[] args) {
        MyLinkedList list = new MyLinkedList();
        list.append(1);
        list.append(2);
        list.append(3);
        list.append(4);
     list.update(4,1);
//        list.insert(0,29);
        /*list.insert(2,9);
        list.insert(7,6);*/
//        list.update(3,9);
        System.out.println(list);
    }
}

基于C#实现的单向链表

节点类

	/// <summary>
    /// 节点类
    /// </summary>
    class Node
    {
        public Node() { }
        public Node(Object element) {
            this.Element = element;
        }

        // 节点中的元素
        public Object Element { get; set; }
        //下一个节点的指向
        public Object Next { get; set; }

        public override string ToString()
        {
            return "Node{"+
                "element: " + Element +
                ",next: " + Next +
                "}";
        }
    }

单向链表类:

    /// <summary>
    /// 实现单向链表
    /// </summary>
    class MyLinkedList
    {
        // 头节点
        public Object Head { get; set; }

        // 链表的元素个数
        public int Length { get; set; }
        public override string ToString()
        {
            return "MyLinkedList{" +
                "length=" + Length +
                ", head=" + Head +
                "}";
        }

        /// <summary>
        /// 添加一个元素
        /// </summary>
        /// <param name="element">添加的元素</param>
        public virtual void Append(Object element) {
            // 创建一个节点对象
            Node node = new Node(element);
            // 判断链表中是否有值
            if(this.Head == null)
            {
                // 没有值,直接将node节点指向头节点
                this.Head = node;
            }else
            {
                // 有值的情况
                Node current = (Node)this.Head;
                while(current.Next != null)
                {
                    current = (Node)current.Next;
                }
                current.Next = node;
            }
            // 链表长度+1
            this.Length ++;
        }
        /// <summary>
        /// 向指定位置插入一个元素
        /// </summary>
        /// <param name="position">插入元素的位置</param>
        /// <param name="element">插入到元素</param>
        /// <returns></returns>
        public virtual bool Insert(int position,Object element)
        {
            // 判断是否越界
            if(position < 0 || position > Length)
            {
                // 实际情况还需要做异常处理
                Console.Error.WriteLine("插入位置不合法");
                return false;
            }
            Node node = new Node(element);
            // 插入第一个位置
            if(position == 0)
            {
                // 获取头节点
                Node firstNode = (Node)this.Head;
                this.Head = node;
                node.Next = firstNode;
            }else
            {
                // 当前节点
                Node current = (Node)this.Head;
                // 用于记录current的前一个节点
                Node preNode = null;
                for(int i = 0;i < position; i++)
                {
                    preNode = current;
                    current = (Node)current.Next;
                }
                preNode.Next = node;
                node.Next = current;
            }
            this.Length++;
            return true;
        }

        /// <summary>
        /// 根据下标获取对应位置的元素
        /// </summary>
        /// <param name="position">下标值</param>
        /// <returns></returns>
        public virtual Object Get(int position)
        {
            // 判断下标是否越界
            if(position < 0||position > this.Length-1)
            {
                Console.Error.WriteLine("下标不合法");
                return null;
            }
            
            Node current = (Node)this.Head;
            for(int i = 0;i < position; i++)
            {
                current = (Node)current.Next;
            }
            return current.Element;
        }

        /// <summary>
        /// 返回元素在列表中的索引,如果没有就返回-1
        /// </summary>
        /// <param name="element">元素</param>
        /// <returns></returns>
        public virtual int IndexOf(Object element)
        {
            Node current = (Node)this.Head;
            int index = 0;
            while(index < this.Length)
            {
                if (current.Element.Equals(element))
                {
                    return index;
                }
                index++;
                current = (Node)current.Next;
            }
            return -1;
        }

        /// <summary>
        /// 根据下标删除元素
        /// </summary>
        /// <param name="position">删除元素的位置</param>
        /// <returns></returns>
        public virtual Object RomoveAt(int position)
        {
            // 判断下标是否合法
            if(position < 0||position > this.Length - 1)
            {
                Console.Error.WriteLine("下标值不合法");
                return null;
            }
            Node current = (Node)this.Head;
            if (position == 0)
            {
                this.Head = current.Next;
                this.Length--;
                return current.Element;
            }
            Node prevNode = null;
            for(int i = 0;i < position; i++)
            {
                prevNode = current;
                current = (Node)current.Next;
            }
            prevNode.Next = current.Next;
            this.Length--;
            return prevNode.Element;
        }

        /// <summary>
        /// 根据下标修改元素
        /// </summary>
        /// <param name="position"></param>
        /// <param name="newElement"></param>
        /// <returns></returns>
        public virtual bool Update(int position,Object newElement)
        {
            // 先删除该位置元素
            Object result = this.RomoveAt(position);
            //再在该位置插入新的元素
            return result != null ? this.Insert(position, newElement) : false;
        }
        
        /// <summary>
        /// 删除元素
        /// </summary>
        /// <param name="element"></param>
        /// <returns>删除的元素下标</returns>
        public virtual int Remove(Object element)
        {
            // 获取下标
            int index = this.IndexOf(element);
            if (index == -1)
            {
                Console.Error.WriteLine("没有该元素");
            }else
            {
                // 根据下标删除元素
                this.RomoveAt(index);
            }
            return index;
        }

        /// <summary>
        /// 判断链表是否为空
        /// </summary>
        /// <returns></returns>
        public virtual bool IsEmpty()
        {
            return this.Length <= 0;
        }

        /// <summary>
        /// 获取元素的个数
        /// </summary>
        /// <returns></returns>
        public virtual int Size()
        {
            return this.Length;
        }
    }

双向链表

这里利用继承,在单向链表的基础上实现双向链表。

基于Java实现的双向链表

节点类

class DoubleNode extends Node{
    private DoubleNode prev;

    public DoubleNode() {
    }

    public DoubleNode(Object element) {
        super(element);
    }

    public DoubleNode getPrev() {
        return prev;
    }

    public void setPrev(DoubleNode prev) {
        this.prev = prev;
    }
}

链表类:

class DoubleLinkedList extends MyLinkedList{

    private DoubleNode tail;

    public Object getTail() {
        return tail;
    }

    public void setTail(DoubleNode tail) {
        this.tail = tail;
    }

    @Override
    public String toString() {
        return "DoubleLinkedList{" +
                "length=" + this.getLength() +
                ", head=" + this.getHead() +
                ", tail=" + tail +
                '}';
    }

    @Override
    public void append(Object element) {
        DoubleNode node = new DoubleNode(element);
        if (this.getLength() == 0) {
            this.setHead(node);
            this.tail = node;
        }else {
            this.tail.setNext(node);
            node.setPrev(this.tail);
            this.tail = node;
        }

        this.setLength(this.getLength()+1);
    }

    @Override
    public boolean insert(int position, Object element) {
        DoubleNode node = new DoubleNode(element);
        if (position < 0||position > this.getLength()) {
            System.err.println("数组下标越界啦");
            return false;
        }
        DoubleNode current = (DoubleNode)this.getHead();
        if (position == 0) {
            this.setHead(node);
            node.setNext(current);
            current.setPrev(node);
            this.setLength(this.getLength()+1);
            return true;
        }
        if(position == this.getLength()) {
            this.append(element);
        }
        if(position == 0&&this.getLength() == 0) {
            this.setHead(node);
            this.tail = node;
        }else{
            for (int i = 0; i < position; i++) {
                current = (DoubleNode) current.getNext();
            }
            current.getPrev().setNext(node);
            node.setNext(current);
            current.setPrev(node);
        }
        this.setLength(this.getLength()+1);
        return true;
    }


    @Override
    public Object removeAt(int position) {
        if (position <0 || position > this.getLength()-1) {
            System.err.println("数组下标越界啦!");
            return false;
        }
        DoubleNode current = (DoubleNode) this.getHead();
        if (position == 0&&this.getLength() == 0) {
            this.setHead(null);
            this.tail = null;
            this.setLength(this.getLength()-1);
            return current.getElement();
        }else if (position == this.getLength()-1){
            // 获取尾节点
            DoubleNode tailNode = this.tail;
            tailNode.getPrev().setNext(null);
            this.tail = tailNode.getPrev();
            this.setLength(this.getLength()-1);
            return tailNode.getElement();
        }else if(position == 0) {
            this.setHead(current.getNext());
            ((DoubleNode)current.getNext()).setPrev(null);
            this.setLength(this.getLength()-1);
            return current.getElement();
        }
        for (int i = 0; i < position; i++) {
            current = (DoubleNode) current.getNext();
        }
        DoubleNode prev = current.getPrev();
        prev.setNext(current.getNext());
        DoubleNode n = (DoubleNode)current.getNext();
        n.setPrev(prev);
        this.setLength(this.getLength()-1);
        return current.getElement();
    }





    public static void main(String[] args) {
        DoubleLinkedList list = new DoubleLinkedList();
        list.append(1);
        list.append(2);
        list.append(3);
//        list.insert(0,9);

       /* System.out.println(list.get(3));
        System.out.println(list.indexOf(9));*/

        Object o = list.removeAt(1);
        System.out.println(o);

//        System.out.println(list.update(1, 20));
//        list.update(3,20);
        System.out.println(list);

    }
}

基于C#实现的双向链表

节点类

	/// <summary>
    /// 继承自Node
    /// </summary>
    class DoubleNode:Node
    {
        public DoubleNode() { }
        public DoubleNode(Object element)
        {
            this.Element = element;
        }
        // 存放当前节点前一个节点的引用
        public Object Prev { get; set; }
    }

链表类:

 	/// <summary>
    /// 继承自MyLinkedList
    /// </summary>
    class DoubleLinkedList:MyLinkedList
    {
        // 尾节点
        public Object Tail { get; set; }

        public override string ToString()
        {
            return "DoubleLinkedList{" +
                "length=" + Length +
                ", head=" + Head +
                ", tail=" + Tail +
                "}";
        }

        /// <summary>
        /// 向链表中追加元素
        /// </summary>
        /// <param name="element">元素</param>
        public override void Append(Object element)
        {
            DoubleNode node = new DoubleNode(element);
            // 链表为空
            if(this.Length == 0)
            {
                this.Head = node;
                this.Tail = node;
            }else
            {
                // 链表不为空,获取尾部节点
                DoubleNode tailNode = (DoubleNode)this.Tail;
                tailNode.Next = node;
                node.Prev = tailNode;
                this.Tail = node;
               
            }
            this.Length++;
        }

        ///
        public override bool Insert(int position, object element)
        {
            DoubleNode node = new DoubleNode(element);
            //判断下标是否越界
            if(position < 0||position > this.Length)
            {
                Console.Error.WriteLine("下标越界");
                return false;
            }
            //链表中没有元素
            if(this.Length == 0)
            {
                this.Head = node;
                this.Tail = node;
                this.Length++;
                return true;
            }
            // 插入到头部
            if(position == 0)
            {
                DoubleNode headNode = (DoubleNode)this.Head;
                this.Head = node;
                node.Next = headNode;
                headNode.Prev = node;
                this.Length++;
                return true;
            }
            // 插入到尾部
            if(position == this.Length)
            {
                this.Append(element);
                return true;
            }
            // 插入到中间
            DoubleNode current = (DoubleNode)this.Head;
            for (int i = 0; i < position; i++)
            {
                current = (DoubleNode)current.Next;
            }
            // 获取当前位置的前一个节点
            DoubleNode prevNode = (DoubleNode)current.Prev;
            prevNode.Next = node;
            node.Prev = prevNode;
            node.Next = current;
            current.Prev = node;
            this.Length++;
            return true;
        }

        public override object RomoveAt(int position)
        {
            // 判断下标是否合法
            if(position < 0 ||position > this.Length-1)
            {
                Console.Error.WriteLine("下标不合法");
                return null;
            }
            // 删除头部元素
            if(position == 0)
            {
                DoubleNode headNode = (DoubleNode)this.Head;
                headNode.Prev = null;
                this.Head = headNode.Next;
                this.Length--;
                return headNode.Element;
            }

            // 删除尾部元素
            if (position == this.Length - 1)
            {
                DoubleNode tailNode = (DoubleNode)this.Tail;
                // 获取尾部节点的上一个节点
                DoubleNode prev = (DoubleNode)tailNode.Prev;
                prev.Next = null;
                this.Tail = prev;
                this.Length--;
                return tailNode.Element;
            }

            DoubleNode current = (DoubleNode)this.Head;
            // 删除中间的元素
            for(int i = 0;i < position; i++)
            {
                current = (DoubleNode)current.Next;
            }
            // 获取当前节点的上一个节点
            DoubleNode prevN = (DoubleNode)current.Prev;
            // 获取当前节点的下一个节点
            DoubleNode nextN = (DoubleNode)current.Next;
            prevN.Next = nextN;
            nextN.Prev = prevN;
            this.Length--;
            return current.Element;
        }
    }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值