• 数组与单、双链表详解


    一、数组

    数组的定义

    格式一:

    元素类型[] 数组名 = new 元素类型[元素的个数或数组长度]

    示例:

    int[] array1 = new int[2];
    array1[0]=1;
    array1[1]=2;
    array1[2]=3;
    

    格式二:

    元素类型[] 数组名 = new 元素类型[]{元素,元素,……};

    示例:

    int[] arr = new int[]{3,5,1,7};
    int[] arr = {3,5,1,7};
    

    注意:给数组分配空间时,必须指定数组能够存储的元素个数来确定数组大小。创建数组之后不能修改数组的大小。可以使用length属性获取数组的大小

    数组的优缺点

    优点

    • 随机访问性强(通过下标进行快速定位)
    • 查找速度快

    缺点

    • 插入和删除效率低(插入和删除需要移动数据)
    • 可能浪费内存(因为是连续的,所以每次申请数组之前必须规定数组的大小,如果大小不合理,则可能会浪费内存)
    • 内存空间要求高,必须有足够的连续内存空间。
    • 数组大小固定,不能动态拓展

    二、链表

    普及一下
    线性表分为顺序存储(顺序表)和链式存储(单链表、双链表、循环链表、静态链表,前面三种指针实现,后面是借助数组实现)

    1、单链表

    单链表只有一个指向下一节点的指针,也就是只能next

    定义单链表

    首先定义一个Node类

     public class Node {
     protected Node next; //指针域  
     public  int data;//数据域  
       
     public Node( int data) {  
           this. data = data;  
     }  
       
     //显示此节点  
     public void display() {  
          System. out.print( data + " ");  
     }  
    }
    

    接下来定义一个单链表

    public class LinkList {
    public Node first; // 定义一个头结点
    private int pos = 0;// 节点的位置
    
    public LinkList() {
        this.first = null;
    }
    
    // 插入一个头节点
    public void addFirstNode(int data) {
        Node node = new Node(data);
        node.next = first;
        first = node;
    }
    
    // 删除一个头结点,并返回头结点
    public Node deleteFirstNode() {
        Node tempNode = first;
        first = tempNode.next;
        return tempNode;
    }
    
    // 在任意位置插入节点 在index的后面插入
    public void add(int index, int data) {
        Node node = new Node(data);
        Node current = first;
        Node previous = first;
        while (pos != index) {
            previous = current;
            current = current.next;
            pos++;
        }
        node.next = current;
        previous.next = node;
        pos = 0;
    }
    
    // 删除任意位置的节点
    public Node deleteByPos(int index) {
        Node current = first;
        Node previous = first;
        while (pos != index) {
            pos++;
            previous = current;
            current = current.next;
        }
        if (current == first) {
            first = first.next;
        } else {
            pos = 0;
            previous.next = current.next;
        }
        return current;
    }
    
    // 根据节点的data删除节点(仅仅删除第一个)
    public Node deleteByData(int data) {
        Node current = first;
        Node previous = first; // 记住上一个节点
        while (current.data != data) {
            if (current.next == null) {
                return null;
            }
            previous = current;
            current = current.next;
        }
        if (current == first) {
            first = first.next;
        } else {
            previous.next = current.next;
        }
        return current;
    }
    
    // 显示出所有的节点信息
    public void displayAllNodes() {
        Node current = first;
        while (current != null) {
            current.display();
            current = current.next;
        }
        System.out.println();
    }
    
    // 根据位置查找节点信息
    public Node findByPos(int index) {
        Node current = first;
        if (pos != index) {
            current = current.next;
            pos++;
        }
        return current;
    }
    
    // 根据数据查找节点信息
    public Node findByData(int data) {
        Node current = first;
        while (current.data != data) {
            if (current.next == null)
                return null;
            current = current.next;
        }
        return current;
    }
    }
    

    测试类

    public class TestLinkList {
    public static void main(String[] args) {  
        LinkList linkList = new LinkList();  
        linkList.addFirstNode(20);  
        linkList.addFirstNode(21);  
        linkList.addFirstNode(19);  
         //print19,21,20  
        linkList.add(1, 22); //print19,22,21,20  
        linkList.add(2, 23); //print19,22,23,21,20  
        linkList.add(3, 99); //print19,22,23,99,21,20  
      //调用此方法会print 19,22,23,99,21,20 
        linkList.displayAllNodes();  
        }
    }
    

    2、双链表

    双链表除了有一个指向下一节点的指针外,还有一个指向前一结点的指针,可以通过prev快速找到前一结点

    定义双链表

    首先定义一个Node类

    public class Node{
        public Node data;	//数据区
        public Node next; 	//指针区
        public Node (Node data,Node next){
            this.data = data ;
            this.next = next;
        }
        public Node(){
        }
        public void setData(Node data){
            this.data = data;
        }
        public Node getData(){
        	return data;
        }
        public void setNext(Node next){
    	    this.next=next;
        }
        public Node getNext(){
        	return next;
        }
    }
    

    定义一个双链表

    public class LinkList{
    public  Node  head;	//头节点
    public  int  count;		//记录节点的长度
    public  LinkList(){	//构造函数用来初始化
    	head = null;
    	count = 0;
    }
    //节点的添加
    public void addNode(Node data){
    	Node node = new Node(data,null);
    	Node temp = null;
    	If(head!= null){
    		temp = head;
    		while(temp.getNext()!=null){
    			Temp = temp.getNext();
    		}
    	temp.setNext(node);
    	}else{
    		head = node;
    		temp = node;
    	}
    count++;
    }
    //节点的删除
    public void delNode(Node data){
    	
    		Node  front = null;	//定义一个空节点,用于接收和判断被删除节点的前面还有没有节点
    		while(head!= null){
    			If(head.equals(data)){
    				break;
    			}
    			front=head;
    			head = head.getNext();
    		}
    		If(head!=null){
    			If(front==null){
    				head = head.getNext();
    			}else{
    				front.setNext(head.getNext());
    			}
    			count--;
    		}else{
    			Count--;
    		}
    	
    }
    //给定下标删除节点
    public void delNode_count(int index){
    	if(index<0||index>count-1){
    		System.out.println("链表索引越界");
    	}
    	Node temp = head;	//作用同上
    	//找到要删除节点的前一个节点
    	for(int i=0;i<index-1;i++){
    		temp=temp.getNext();
    	}
    							//找到之后 此节点的前节点和此节点的后节点进行连接
    							//让要删除节点的前一个节点,指向被删除节点的后一个节点,也就是指向要删除节点的后后一个节点
    	temp.setNext(temp.getNext().getNext());		//把要删除的节点隔过去进行连接,也就是实现了删除节点的操作
    	//删除之后链表的长度变短了1位
    	count--;
    }
    	//以给出的index 查找节点
    
    
    public Node findNode(int index){
    	if(index<0||index>count-1){
    		System.out.println("链表索引越界");			
    	}
    	Node temp = head;
    	for(int i=0;i<index-1;i++){
    		temp=temp.getNext();	//找到之后获取index在链表中的位置,表示链表中第index个节点的值是temp.getData;
    	}
    	return temp;	//根据需要可返回找到的数据对象,也可不返回,此处建议返回,这样可以把链表封装起来
    }
    
    //以对象查找节点
    public Node findNode(NodeData data){
    		Node temp = head;
    		while(temp!=null){
    			if(temp.equals(data)){
    				return temp;
    			}
    			temp.setNext(temp.getNext());
    		}
    		return null;
    }
    //修改
    public void updateNode(NodeData data){
    	Node temp = findNode(data);
    	if(temp!=null){
    		temp.setData(data);
    	}
    }
    //打印
    public void print(){
    	Node temp=head;
    	while(temp!=null){
    		temp.print();
    		//temp.print(temp.getData().toString());
    		temp=temp.getNext();
    	}
    }
    }
    

    3、链表相对于数组的优缺点

    时间复杂度对比

    操作 数组 链表
    读取 O(1) O(n)
    插入 O(n) O(1)
    删除 O(n) O(1)

    优点

    • 插入删除速度快(因为有next指针指向其下一个节点,通过改变指针的指向可以方便的增加删除元素)
    • 内存利用率高,不会浪费内存(可以使用内存中细小的不连续空间(大于node节点的大小),并且在需要空间的时候才创建空间)
    • 大小没有固定,拓展很灵活。

    缺点

    • 不能随机查找,必须从第一个开始遍历,查找效率低

    4、单链表与双链表的区别

    单链表只有一个指向下一结点的指针,也就是只能next

    双链表除了有一个指向下一结点的指针外,还有一个指向前一结点的指针,可以通过prev()快速找到前一结点,顾名思义,单链表只能单向读取

    双链表的优点

    • 删除单链表中的某个结点时,一定要得到待删除结点的前驱,得到该前驱有两种方法,第一种方法是在定位待删除结点的同时一路保存当前结点的前驱。第二种方法是在定位到待删除结点之后,重新从单链表表头开始来定位前驱。尽管通常会采用方法一。但其实这两种方法的效率是一样的,指针的总的移动操作都会有2*i次。而如果用双向链表,则不需要定位前驱结点。因此指针总的移动操作为i次。
    • 查找时也一样,我们可以借用二分法的思路,从中间节点开始前后同时查找,这样双链表的效率可以提高一倍。

    单链表的优点

    • 从存储结构来看,每个双链表的节点要比单链表的节点多一个指针,而长度为n就需要 n*length(这个指针的length在32位系统中是4字节,在64位系统中是8个字节) 的空间,这在一些追求时间效率不高应用下并不适应,因为它占用空间大于单链表所占用的空间;这时设计者就会采用以时间换空间的做法,这时一种工程总体上的衡量。
  • 相关阅读:
    (15)疯狂的程序员----《绝影》
    (14)嵌入式软件开发工程师技能要求总结
    (13)碎片化阅读只会让你变得越来越愚蠢
    (12)QT中搭建opencv开发环境
    (11)git服务器的安装和配置
    (10)python学习笔记一
    (3.3)狄泰软件学院C++课程学习剖析四
    (9)Linux下gdb调试学习
    (8)Linux(客户端)和Windows(服务端)下socket通信实例
    springMVC伪静态
  • 原文地址:https://www.cnblogs.com/sxkgeek/p/9347071.html
Copyright © 2020-2023  润新知