从零开始学数据结构和算法(二)线性表的链式存储结构

*/
public class Mahjong {
public int suit;//筒,万,索
public int rank;//点数 一 二 三

public Mahjong(int suit, int rank) {
this.suit = suit;
this.rank = rank;
}

@Override
public String toString() {
return “(”+this.suit+" “+this.rank+”)";
}
}

/**

  • 用系统自带的 链表结构 LinkedList 来进行将麻将排序
  • @param list
    */
    private void radixSort(LinkedList list) {
    //1. 先把所有的点数分别装入到对应的链表组中
    //创建一个点数最大的为 9 的集合
    LinkedList[] linkedList = new LinkedList[9];
    //先初始化这 9 个链表目的是装所有的对应的点数
    for (int i = 0; i < 9; i++) {
    linkedList[i] = new LinkedList();
    }
    while (list.size() > 0) {
    //取出对应的元素放入到链表中
    Mahjong mahjong = list.remove();
    //mahjong.rank - 1 的意思就是对应的集合下标
    linkedList[mahjong.rank - 1].add(mahjong);
    }

//2. 然后再把所有的链表中的点数合并在一起
for (int i = 0; i < linkedList.length; i++) {
list.addAll(linkedList[i]);
}

//3. 在把所有的点数分别装入到对应的链表中
//花色有 3 个,那么我们就创建 3 个链表来代表装入对应的花色
LinkedList[] linkedLists =new LinkedList[3];
for (int i = 0; i < 3; i++) {
linkedLists[i] = new LinkedList();
}

//把对应的花色装在对应的链表中
while (list.size()>0){
Mahjong mahjong = list.remove();
linkedLists[mahjong.suit - 1].add(mahjong);
}

//4. 最后在把对应的点数链表装在一个新的集合中
for (int i = 0; i < linkedLists.length; i++) {
list.addAll(linkedLists[i]);
}
}

  • 应用

数据量几十个,插入操作多的情况

编写双向链表 LinkedList CURD

  • 参考图解

  • 编写代码

/**

  • Created by yangk on 2019/1/29.
  • 自己定义的双向链表结构 LinkedList
    */

public class CustomLinkedList {

/**

  • 链表的头部
    */
    transient Node head;

/**

  • 链表的尾部
    */
    transient Node tail;

/**

  • 当前链表的大小
    */
    transient int size;

/**

  • 存入数据
    */
    public boolean add(E e) {
    linkLast(e);
    return true;
    }

/**

  • 返回当前链表的大小
  • @return
    */
    public int getSize() {
    return size;
    }

/**

  • 将当前数据存入到链表的头部
  • @param e
    */
    public void addFirst(E e) {
    Node h = head;
    //创建新节点
    Node newNode = new Node<>(null, e, head);
    head = newNode;

if (head == null) {
tail = newNode;
} else {
h.pre = newNode;
}
size++;
}

/**

  • 根据索引搜索到的节点数据
  • @param index
    */
    public E get(int index) {
    if (isPositionIndex(index)) {
    return searchNode(index).data;
    }
    return null;
    }

/**

  • 根据索引添加数据
  • @param index
  • @param e
    */
    public void add(int index, E e) {
    addIndex(index, e);
    }

/**

  • 删除第一个节点
    */
    public E remove() {
    return removeFirst();
    }

/**

  • 删除头节点
  • @return
    */
    private E removeFirst() {
    Node h = head;
    if (h == null)
    throw new NoSuchElementException();
    return unlinkFirst(h);
    }

private E unlinkFirst(Node h) {
//删除的 数据
E deleData = h.data;
//找到要删除的后驱
Node next = h.next;

//清理节点
h.data = null;
h.next = null;

//将当前要删除的后驱置为链表头
head = next;

if (next == null) {
tail = null;
} else {
next.pre = null;
}
h = null;

size–;
return deleData;
}

private void addIndex(int index, E e) {
if (isPositionIndex(index)) {
//找到当前需要插入的索引位置
if (index == size) {
linkLast(e);
} else {
add(e, searchNode(index));
}
}
}

/**

  • 添加新节点到 searchNode 前驱
  • @param e
  • @param searchNode
    */
    private void add(E e, Node searchNode) {
    //找到 searchNode 前驱节点
    Node snPre = searchNode.pre;
    //创建新节点
    Node newNode = new Node<>(snPre, e, searchNode);
    searchNode.pre = newNode;
    //这里判断 snPre 是否为空 入股为空说明 head 没有数据,如果有数据 就直接把 snPre . next() = newNode
    if (snPre == null) {
    head = newNode;
    } else {
    snPre.next = newNode;
    }
    size++;
    }

private Node searchNode(int index) {
//优化寻找节点 如果 index > size / 2 就从尾部开始查询,反之从 head 开始遍历查询
if (index > (size >> 1)) {
Node t = tail;
for (int i = size - 1; i > index; i–) {
t = t.pre;
}
return t;
} else {
Node h = head;
for (int i = 0; i < index; i++) {
h = h.next;
}
return h;
}
}

/**

  • 将数据存入到当前链表尾部
  • @param e
    */
    private void linkLast(E e) {
    //拿到尾部的节点数据
    Node t = tail;
    //创建新的节点数据,因为是存在当前节点的尾部,
    // 那么直接默认将当前添加进来的 E 的前驱设置为
    // 当前链表中的尾部数据,现在已经形成单链表了
    // 下一步直接形成双向链表
    Node newNode = new Node<>(t, e, null);
    //现在是双向链表,要把新的节点指向当前的尾部节点,尾部节点指向新的节点
    tail = newNode;

//如果尾部节点为空 那么说明 head 也是空数据 那就吧新节点数据赋值给 head
if (t == null) {
head = newNode;
} else {
t.next = newNode;
}
size++;
}

/**

  • 创建一个空的构造者
    */
    public CustomLinkedList() {
    }

private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}

/**

  • 定义一个内部节点
  • 双向链表需要前驱,后驱,数据
    /
    public static class Node {
    /
    *
  • 当前节点的前驱
    /
    private Node pre;
    /
    *
  • 当前节点的数据
    /
    private E data;
    /
    *
  • 当前节点的后驱
    */
    private Node next;

public Node(Node pre, E data, Node last) {
this.pre = pre;
this.data = data;
this.next = last;
}
}
}

  • 测试代码

@Test
public void testCustomLinkedList() {
CustomLinkedList linkedList = new CustomLinkedList();
linkedList.add(22);
linkedList.add(2);
linkedList.add(77);
linkedList.add(6);
linkedList.add(43);
linkedList.add(76);
linkedList.add(89);

linkedList.add(0,0);

for (int i = 0; i < linkedList.size; i++) {
int integer = linkedList.get(i);
System.out.println(“–CustomLinkedList–CustomLinkedList” +integer+“”);
}
System.out.println(“\n\n”);
Integer remove = linkedList.remove();
System.out.println(“–CustomLinkedList–CustomLinkedList” +remove);
Integer remove1 = linkedList.remove();
System.out.println(“–CustomLinkedList–CustomLinkedList” +remove1+“”);
Integer remove2 = linkedList.remove();
System.out.println(“–CustomLinkedList–CustomLinkedList” + remove2 + “”);

System.out.println(“\n\n”);
for (int i = 0; i < linkedList.size; i++) {
int integer = linkedList.get(i);
System.out.println(“–CustomLinkedList–CustomLinkedList” +integer+“”);
}
}

  • 测试结果

编写简单的 ArrayList CURD

public class CustomArrayList {

/**

  • 默认的空元素对象
    */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**

  • 空元素数据
    */
    private static final Object[] EMPTY_ELEMENTDATA = {};

/**

  • 默认的元素对象
    */
    private Object[] elementData = null;

/**

  • 容量大小
    */
    private int size = 0;

/**

  • 默认的容量大小
    */
    private static final int DEFAULT_CAPACITY = 10;

/**

  • 最大的数量
  • TODO------------减 8 是什么意思没有搞懂
    */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**

  • 赋值为一个空对象
    */
    public CustomArrayList(){
    elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

/**

  • 外部指定初始化一个容量大小
  • @param initCapacity
    */
    public CustomArrayList(int initCapacity){
    if (initCapacity > 0){
    elementData = new Object[initCapacity];
    }else if (initCapacity == 0){
    elementData = EMPTY_ELEMENTDATA;
    }else {
    throw new IllegalArgumentException("Illegal Capacity: "+
    initCapacity);
    }
    }

/**

  • 添加数据
    */
    public boolean add(E e){
    //判断是否需要开辟容量空间
    checkIsNeedCapacity(size + 1);
    //添加添加数据
    elementData[size++] = e;

return true;
}

private void checkIsNeedCapacity(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA){
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}

ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {

// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

/**

  • 开辟空间的核心代码
  • @param minCapacity
    */
    private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
    newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
同时减轻大家的负担。**

[外链图片转存中…(img-srVw5dxN-1715882533167)]

[外链图片转存中…(img-IzH7Bvgm-1715882533168)]

[外链图片转存中…(img-JAVsykt5-1715882533169)]

[外链图片转存中…(img-PDY50qK0-1715882533170)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值