数组与链表

1 篇文章 0 订阅

数组与链表

数组的本质是固定大小的连续的内存空间,并且这片连续的内存空间又被分割成等长的小空间。

特点是:连续存储,进一步,主要的特点是随机访问

为什么连续的内存空间又被分割成等长的小空间

(1)数组的长度是固定的

(2)数组只能存储同一种数据类型的元素

注意:在Java中只有一维数组的内存空间是连续,多维数组的内存空间不一定连续。

那么数组又是如何实现随机访问的呢

寻址公式:i_address = base_address + i * type_length

(基础地址+单个单元长度*下标)

为什么数组的索引是一般都是从0开始的呢?

假设索引不是从0开始的,而是从1开始的,那么我们有两种处理方式:
寻址公式变为: i_address = base_address + (i – 1) * type_length

浪费开头的一个内存空间,寻址公式不变。

在计算机发展的初期,不管是CPU资源,还是内存资源都极为宝贵,所以在设计编程语言的时候,索引就从0开始了,而我们也一直延续了下来。

为什么数组的效率比链表高?

本质:数组是连续存储, 链表是非连续存储。 

数组的基本操作

添加 (保证元素的顺序)
最好情况:O(1)
最坏情况:移动n个元素,O(n)
平均情况:移动 n/2 个元素,O(n)

删除 (保证元素的顺序)
最好情况:O(1)
最坏情况:移动n-1个元素,O(n)
平均情况:移动(n-1)/2个元素,O(n)

查找
a. 根据索引查找元素:O(1)
b. 查找数组中与特定值相等的元素
①大小无序:O(n)
②大小有序:O(log2n)

总结: 数组增删慢,查找快。

循环链表我们用的一般比较少,但是当处理的数据具有环形结构时,就特别适合用循环链表
比如约瑟夫问题。

接下来我们讨论下单链表和双向链表。

单链表:

增加(在某个结点后面添加) O(1)

添加头结点:
    Node newNode=new Node(“ ”,top);
    top=newNode;
添加尾结点:
	Node newNode=new Node(“ ”,null);
	mid.next=newNode;
中间添加结点:
	//创建了一个新结点,指向前一个结点的next
	Node newNode=new Node(“ ",midF.next)
	//然后将前一个节点的next指向自己
	midF.next=newNode;

删除(在某个结点后面删除) O(1)

删除头结点:
	top=top.next//头指针指向下一个结点就行
删除尾结点:
	midF.next=null //尾部前一个结点指向空就行
删除中间结点:
	midF.next=midF.next.next//前一个结点的指针指向下下个结点

查找(可能是2/n)
a. 根据索引查找元素 O(n)
b. 查找链表中与特定值相等的元素
①元素大小有序 O(n)
②元素大小无序 O(n)

总结:链表增删快,查找慢。

双向链表:(head end)

前面那些操作,双向链表和单链表的时间复杂度是一样的。那为什么在工程上,我们用的一般是双向链表而不是单链表呢 (比如JDK中的 LinkedList & LinkedHashMap)?

那自然是双向链表有单链表没有的独特魅力——它有一条指向前驱结点的链接。

增加 (在某个结点前面添加元素)

添加头结点:
	Node newNode=new Node(null," ",head)//创建一个新结点
	head.pre=newNode//先将原头结点前指针指向新结点
	head=newNode//把头结点设置为新结点。
添加尾结点:
    Node newNode=new Node(end," ",null)
    end.next=newNode//原end结点的后指针指向新结点
    end=newNode//把尾结点设置为新结点。
添加中间结点:
	//创建一个新结点,前指向mid前一个结点,后指针指向mid结点
	Node newNode=new Node(mid.pre," ",mid)
	//将结点的前一个结点的后指针指向新结点,将原结点的前指针指向新结点
	mid.pre.next=newNode;
	mid.pre=newNode;

删除 (删除该结点)

删除中间结点:
	mid.pre.next=mid.next//前结点的后指针指向后结点
	mid.next.pre=mid.pre//后结点的前指针指向前结点
删除头结点:
    head.next.pre=null;//将下一个结点的前指针指向null
	head=head.next;//设置头结点是下一个节点
删除尾结点:
    end.pre.next=null;//将尾结点前一个结点的后指针指向null
    end=end.pre;//将尾结点设置是前一个结点。

查找(实际时间复杂度可能是4/n)
a. 查找前驱结点 O(n)
b. 根据索引查找元素
c. 查找链表中与特定值相等的元素
① 元素大小无序
② 元素大小有序

总结:虽然双向链表更占用内存空间,但是它在某些操作上的性能是优于单链表的。
思想:用空间换取时间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值