1.什么是数据结构
数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。
数据结构的逻辑结构: 指反映数据元素之间的逻辑关系的数据结构,其中的逻辑关系是指数据元素之间的前后关系,而与他们在计算机中的存储位置无关。逻辑结构包括:
数据的物理结构: 指数据的逻辑结构在计算机存储空间的存放形式.
2.为什么要学数据结构
1. 数据结构+算法 = 程序
2. 大厂的面试基本都会面试到算法.
下面正式开始................................................................................................
线性表是最简单、最基本、也是最常用的一种线性结构。 线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列,通常记为: (a1,a2,… ai-1,ai,ai+1,…an) ,其中n为表长, n=0 时称为空表。简单来说就是数据元素的排序方式是线性的. 它有两种存储方法:顺序存储和链式存储,它的主要基本操作是插入、删除和检索等。
顺序存储方式(顺序表): 它是把逻辑上相邻的结点存储在物理位置相邻的存储单元里,结点间的逻辑关系由存储单元的邻接关系来体现,由此得到的存储表示称为顺序存储结构。顺序存储结构是一种最基本的存储表示方法,通常借助于程序设计语言中的数组来实现.
链接存储方法(链表):它不要求逻辑上相邻的结点在物理位置上亦相邻,结点间的逻辑关系是由附加的指针字段表示的。由此得到的存储表示称为链式存储结构,链式存储结构通常借助于程序设计语言中的指针类型来实现
基本思想:元素的存储空间是连续的.在内存中是以顺序存储,内存划分的区域是连续的,顺序表是顺序存储的线性表
代表: ArrayList,Vector,数组,Student[] stus = new Student(){new Student(),new Student(),........}
在某个索引位置添加元素
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
//动态扩容 当数组元素超出时 增加0.5倍
ensureCapacityInternal(size + 1); // Increments modCount!!
//将索引处后面数据向后移动一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
删除某个索引处元素:
public E remove(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
//将数组中的元素从指定位置前移动一位
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
所以,arraylist的优缺点:
优点:
缺点:
链表是链式存储的线性表.包括单链表.单链循环表,双链表,双链循环表
链表的逻辑关系是由节点的指针决定的,节点的指针只指向下一个节点的链表就是单链表。
单链表的应用:MessageQueue。
将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相连的单链表称为单循环链表,简称循环链表。
双链表有2个指针,next指针指向上一个节点,pre指针指向下一个节点。
双链表的应用:LinkedList。
双链循环表是闭环的双链表,它的尾节点的next指针指向头节点,它的头结点的pre指针指向尾节点。
单链表是由一系列节点组成,节点有数据域和指针域 ,例如Message就是一个节点,MessageQueue就是单链表
MessageQueue插入一个节点,主要是
boolean enqueueMessage(Message msg, long when) {
.....
Message prev;
//for 循环是找到message要插入的位置
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
//将message插入到messageQueque中
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
MessageQueue删除一个节点
Message next(){
.....
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
}
自己手写实现
public class SingleLinkedList{ //头节点 private Node first; //尾节点 private Node last; //单链表长度 private int size; //查询 private Node node(int index){ Node resultNode = first; for (int i = 0; i < index; i++) { resultNode = first.next; } return resultNode; } //增加在尾部 private void add(E e){ Node newNode = new Node<>(e,null); Node temp = last; if (temp==null){ first = newNode; last = newNode; }else { temp.next = newNode; } size++; } //增加在某个位置 private void add(E e,int index){ if (index<0||index>size){ throw new IndexOutOfBoundsException(); } if (index==size){ add(e); }else { Node nextNode = node(index); Node preNode = node(index - 1); Node newNode = new Node<>(e,nextNode); preNode.next = newNode; } size++; } //删除索引处的元素 private void remove(int index){ if (index<0||index>size){ throw new IndexOutOfBoundsException(); } Node target = node(index); Node next = target.next; if (index==0||index==size){ if (index==0){ //删除的元素刚好是第0个元素 first = target.next; }else { //集合中只有一个元素 if (node(index-1)==null){ first=null; last=null; size=0; }else { //将最后一个元素置为null node(index-1).next=null; size--; } } }else { node(index-1).next = target.next; size--; } } class Node { private E item; private Node next; public Node(E item, Node next) { this.item = item; this.next = next; } } }
优点:
缺点:
MessageQueue是用来存放延迟消息的,最先发送的消息需要放在链表的最前面,每次取消息就只需要去最前面的数据。一般新插入的消息,都是放在链表的前面。所以查询和插入操作的位置都很靠前,刚好符合单链表的优点。
单链表由于只有首节点,所以倒序比较麻烦。这里有两种方法
//循环倒序 public void reset() { Nodecurr = first; Node last = null; while (curr != null) { Node temp = curr.next; curr.next = last; last = curr; curr = temp; } first = last; } //递归倒序 public Node reset(Node curr) { //结束条件 if (curr == null || curr.next == null) { return curr; } //循环条件 Node tail = reset(curr.next); //循环内容 curr.next.next = curr; curr.next = null; return tail; }
这里我们手写实现一个双链表。
public class LinkedList
/**
* 结点
*/
private static class Node
E item;
Node
Node
public Node(Node
this.item = item;
this.prev = prev;
this.next = next;
}
}
public LinkedList() {
}
//头节点
Node
//尾节点
Node
//大小
int size;
/**
* 添加数据在最后
*/
public void add(E e) {
linkLast(e);
}
/**
* 添加到最后
* @param e
*/
private void linkLast(E e) {
Node
Node
last=newNode;
if(l==null){
first=newNode;
}else {
l.next = newNode;
}
size++;
}
/**
* 查找位置
*/
public E get(int index){
if(index<0 || index>size){
return null;
}
return node(index).item;
}
/**
* 获取index位置上的节点
*/
private Node
//如果index在整个链表的前半部分
if(index<(size>>1)){ //1000 100 10
Node
for (int i = 0; i < index; i++) {
node=node.next;
}
return node;
}else{
Node
for (int i = size-1; i > index; i--) {
node=node.prev;
}
return node;
}
}
/**
* 添加数据在index位置
*/
public void add(int index,E e) {
if(index<0 || index>size){
return ;
}
if(index==size){
linkLast(e);
}else{
Node
Node
Node
if(pre==null){
first=newNode;
target.prev = newNode;//4
}else {
pre.next = newNode;//3
target.prev = newNode;//4
}
size++;
}
}
/**
* 删除元素
*/
public void remove(int index){
Node
unlinkNode(target);
}
private void unlinkNode(Node
Node
Node
if(pre==null){
first=p.next;
}else{
pre.next=p.next;
}
if(next==null){
last=p.prev;
}else{
next.prev=p.prev;
}
size--;
}
}
优点:
缺点: