链表

之前看过了动态数组,栈和队列,虽然我们把第一个叫做动态数组,但是,他们的底层实质上还是静态数组。靠

resize来实现动态数组。而链表是真正的数据结构

  • 链表需要一个节点。
  • 数据存储在链表中

相当于是一串火车,将数据放在车厢中,两个车厢之间还需要一个个节点来相互串联。

优点:实现了真正的动态。

缺点:无法进行随机访问

public class LinkedList<E> {

    private class Node {

        public E e;
public Node next; public Node(E e) {
this(e, null);
} public Node(E e, Node next) {
this.e = e;
this.next = next;
} public Node() {
this(null, null);
} @Override
public String toString() {
return e.toString();
}
} private Node head;
private int size; public LinkedList(Node head, int size) {
head = null;
this.size = 0;
} //获取链表中的元素个数
public int getSize() {
return size;
} //返回链表是否为空
public boolean isEmpty() {
return size == 0;
} //链表添加新的元素
public void addFirst(E e) {
// Node newNode = new Node((E) node);
// newNode.next = head;
// head = newNode; head = new Node(e, head);
size++;
} //在链表的index位置添加新的元素e
//在链表中不是一个常用的操作 :)
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed,Illegal index");
}
if (index == 0) {
addFirst(e);
} else {
Node prev = new Node(e);
for (int i = 0; i < index - 1; i++) {
prev.next = prev;
}
// Node node = new Node(e);
// prev.next = node.next;
// prev.next = node;
prev.next = new Node(e,prev.next); size++;
}
} //在末尾添加元素
public void addLast(E e){
add(size,e);
}

这是自己建立的链表,在此处,一定要注意几点

  • 在增加或删除元素时,不要忘了维护size
  • 再添加链表时,一定不要忘了顺序的问题,一定是先prev.next = node.next.之后才是prev.next = node;
  • 一开始的时候 head = prev

再添加操作时,由于头结点的上一个节点时null,所以我们需要特殊处理,为了解决这个问题,我们增加了一个虚拟

头结点。这个节点不存出任何数据。

public class LinkedList<E> {

    private class Node {

        public E e;
public Node next; public Node(E e) {
this(e, null);
} public Node(E e, Node next) {
this.e = e;
this.next = next;
} public Node() {
this(null, null);
} @Override
public String toString() {
return e.toString();
}
} private Node dummyHead;
private int size; public LinkedList() {
dummyHead = new Node(null, null);
size = 0;
} public LinkedList(Node head, int size) {
head = null;
this.size = 0;
} //获取链表中的元素个数
public int getSize() {
return size;
} //返回链表是否为空
public boolean isEmpty() {
return size == 0;
}
//在链表的index位置添加新的元素e
//在链表中不是一个常用的操作 :)
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed,Illegal index");
} Node prev = dummyHead;
for (int i = 0; i < index; i++) {
prev.next = prev;
}
// Node node = new Node(e);
// prev.next = node.next;
// prev.next = node;
prev.next = new Node(e, prev.next); size++; }
//链表添加新的元素
public void addFirst(E e) {
// Node newNode = new Node((E) node);
// newNode.next = head;
// head = newNode; add(0,e);
size++;
}
//在末尾添加元素
public void addLast(E e) {
add(size, e);
} }

链表的遍历,增 删 改 查。

public class LinkedList<E> {

    private class Node {

        public E e;
public Node next; public Node(E e) {
this(e, null);
} public Node(E e, Node next) {
this.e = e;
this.next = next;
} public Node() {
this(null, null);
} @Override
public String toString() {
return e.toString();
}
} private Node dummyHead;
private int size; public LinkedList() {
dummyHead = new Node();
size = 0;
} //获取链表中的元素个数
public int getSize() {
return size;
} //返回链表是否为空
public boolean isEmpty() {
return size == 0;
} //在链表的index位置添加新的元素e
//在链表中不是一个常用的操作 :)
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed,Illegal index");
} Node prev = dummyHead;
for (int i = 0; i < index; i++) {
prev= prev.next ;
}
// Node node = new Node(e);
// prev.next = node.next;
// prev.next = node;
prev.next = new Node(e, prev.next); size++; } //链表添加新的元素
public void addFirst(E e) {
// Node newNode = new Node((E) node);
// newNode.next = head;
// head = newNode; add(0, e); } //在末尾添加元素
public void addLast(E e) {
add(size, e);
} /**
* 遍历整个列表
* 实际过程中不会这么用
* 仅供联系
*
* @param index
* @return
*/
public E get(int index) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Get failed Illegal index");
}
Node cur = dummyHead.next;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
return cur.e;
} // 获得链表的第一个元素
public E getFirst() {
return get(0);
}
//获取链表的最后一个元素
public E getLast() {
return get(size - 1);
}
//修改链表的第index(0-based)个位置的元素为e
//在链表中不是一个常用的操作,练习用 :)
public void set(int index, E e) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("Set Failed,illegal index");
}
Node cur = dummyHead.next;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
cur.e = e;
}
//参照链表中是否有元素E
public boolean contains(E e){
Node cur = dummyHead.next;
while (cur != null){
if(cur.e.equals(e)){
return true;
}
cur = cur.next;
}
return false;
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
Node cur = dummyHead.next;
while(cur != null){
res.append(cur+"->");
cur = cur.next;
}
res.append("null");
return res.toString();
}
}

之前这些代码我们写完了增 改 查,下面我们就要写删除操作。

 //删除链表中的一个元素
public E remove(int index) {
if (index > 0 || index < size) {
throw new IllegalArgumentException("remove failed");
}
Node prev = dummyHead;
for (int i = 0; i < index; i++) {
prev = prev.next;
}
Node retNode = prev.next;
prev.next = retNode.next;
retNode.next = null;
size--;
return retNode.e;
} //删除链表中的第一个元素
public E removeFirst() {
return remove(0);
} //删除链表中最后一个元素
public E removeLast() {
return remove(size - 1);
}

链表的时间复杂度

  • addLast(e):O(n)
  • addFirst(e):O(1)
  • add(index,e):O(n)
  • setIndex(e):O(n)
  • get(index):O(n)
  • contains(e):O(n)

如果只对链表头进行操作,那么他的时间复杂度是O(1),所以我们来尝试一下利用链表来做栈的可能性。

import java.util.List;

/**
* @author shkstart
* @create 2019-11-29 13:03
*/
public class LinkedListStack<E> implements Stack<E>{ private LinkedList<E> list; public LinkedListStack() {
list = new LinkedList<E>();
} @Override
public int getSize() {
return getSize();
} @Override
public void push(E e) {
list.addFirst(e);
} @Override
public boolean isEmpty() {
return isEmpty();
} @Override
public E pop() {
return list.removeFirst();
} @Override
public E peek() {
return list.getFirst();
} @Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append("stack:top");
res.append(list);
return res.toString();
} public static void main(String[] args) {
LinkedListStack<Integer> stack = new LinkedListStack<Integer>(); for (int i = 0; i < 5; i++) {
stack.push(i);
System.out.println(stack);
} stack.pop();
System.out.println(stack);
}
}

做完了栈,同样的 我们试验一下利用链表实现队列。

 private class Node {

        public E e;
public Node next; public Node(E e, Node next) {
this.e = e;
this.next = next;
} public Node(E e) {
this(e, null);
} public Node() {
this(null, null);
} @Override
public String toString() {
return e.toString();
} } private Node tail, head; private int size; public LinkedListQueue(Node tail, Node head, int size) {
this.tail = null;
this.head = null;
this.size = 0;
} public LinkedListQueue() {
} @Override
public int getSize() {
return getSize();
} @Override
public boolean isEmpty() {
return isEmpty();
} @Override
public void enqueue(E e) {
if (tail.next == null) {
Node node = new Node(e);
tail = head;
} else {
tail.next = new Node(e);
tail = tail.next;
}
size++;
} @Override
public E dequeue() { if (isEmpty()) {
throw new IllegalArgumentException("dequeue出错!");
} Node ret = head;
head = head.next;
ret.next = null;
if (head == null) {
tail = head;
}
size--;
return ret.e;
} @Override
public E getFront() {
if (isEmpty()) {
throw new IllegalArgumentException("Queue is empty");
}
return head.e;
} @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Queue:");
builder.append("front [");
Node cur = head;
while (cur != null) {
cur = cur.next;
}
builder.append("Null tail");
return builder.toString(); } public static void main(String[] args) {
LinkedListQueue<Integer> LinkedListQueue = new LinkedListQueue<Integer>();
for (int i = 0; i < 10; i++) {
LinkedListQueue.enqueue(i);
System.out.println(LinkedListQueue);
if (i % 3 == 2) {
LinkedListQueue.dequeue();
System.out.println(LinkedListQueue);
}
}
}

在这里的链表我们写了尾指针!

学习数据结构Day4的更多相关文章

  1. Spark菜鸟学习营Day4 单元测试程序的编写

    Spark菜鸟学习营Day4 单元测试程序的编写 Spark相比于传统代码是比较难以调试的,单元测试的编写是非常必要的. Step0:需求分析 在测试案例编写前,需完成需求分析工作,明确程序所有的输入 ...

  2. SqList *L 和 SqList * &L的区别/学习数据结构突然发现不太懂 小祥我查找总结了一下

    小祥在学习李春葆的数据结构教程时发现一个小问题,建立顺序表和输出线性表,这两个函数的形参是不一样的. 代码在这里↓↓↓ //定义顺序表L的结构体 typedef struct { Elemtype d ...

  3. 在Object-C中学习数据结构与算法之排序算法

    笔者在学习数据结构与算法时,尝试着将排序算法以动画的形式呈现出来更加方便理解记忆,本文配合Demo 在Object-C中学习数据结构与算法之排序算法阅读更佳. 目录 选择排序 冒泡排序 插入排序 快速 ...

  4. OpenCV图像处理学习笔记-Day4(完结)

    OpenCV图像处理学习笔记-Day4(完结) 第41课:使用OpenCV统计直方图 第42课:绘制OpenCV统计直方图 pass 第43课:使用掩膜的直方图 第44课:掩膜原理及演示 第45课:直 ...

  5. 数据结构之Queue | 让我们一块来学习数据结构

    前面的两篇文章分别介绍了List和Stack,下面让我们一起来学习Queue 数据结构之List | 让我们一块来学习数据结构 数据结构之Stack | 让我们一块来学习数据结构 队列的概况 队列是一 ...

  6. 数据结构之LinkedList | 让我们一块来学习数据结构

    highlight: monokai theme: vue-pro 上一篇文章中使用列表(List)对数据排序,当时底层储存数据的数据结构是数组.本文将讨论另外一种列表:链表.我们会解释为什么有时链表 ...

  7. 数据结构之Set | 让我们一块来学习数据结构

    数组(列表).栈.队列和链表这些顺序数据结构对你来说应该不陌生了.现在我们要学习集合,这是一种不允许值重复的顺序数据结构.我们将要学到如何创建集合这种数据结构,如何添加和移除值,如何搜索值是否存在.你 ...

  8. MySQL 学习 --- 数据结构和索引

    本文参考了多篇文章集成的笔记,希望各位学习之前可以阅读以下参考资料先 概述 文章分几个部分 :第一部分介绍了B-Tree 和 B+Tree 这种数据结构作为索引:第二部分介绍索引的最左前缀原则和覆盖索 ...

  9. 省选算法学习-数据结构-splay

    于是乎,在丧心病狂的noip2017结束之后,我们很快就要迎来更加丧心病狂的省选了-_-|| 所以从写完上一篇博客开始到现在我一直深陷数据结构和网络流的漩涡不能自拔 今天终于想起来写博客(只是懒吧.. ...

随机推荐

  1. hiveSQL常用日期函数

    注意 MM,DD,MO,TU 等要大写 Hive 可以在 where 条件中使用 case when 已知日期 要求日期 语句 结果 本周任意一天 本周一 select date_sub(next_d ...

  2. 解读 v8 排序源码

    前言 v8 是 Chrome 的 JavaScript 引擎,其中关于数组的排序完全采用了 JavaScript 实现. 排序采用的算法跟数组的长度有关,当数组长度小于等于 10 时,采用插入排序,大 ...

  3. sass中的占位符%,@extend,@mixin(@include)的编译区别和使用场景

    对于下面同一段css,它们的编译效率是不同的. 1.使用@extend:基础类icon会出现在编译后的css文件中,即使它可能只是拿来被继承,而不是作为icon这个class单独使用 //基础类ico ...

  4. web自动化测试-selenium多表单切换

    一.概述 1.在web应用中会经常遇到frame/iframe表单嵌套页面的应用 2.WebDriver只能在一个页面上对元素进行识别与定位 3.对于frame/iframe表单内嵌的页面上元素无法识 ...

  5. LOJ P10008 家庭作业 题解

    每日一题 day45 打卡 Analysis 这道题跟LOJ P10004 一样,但是数据范围不同,不允许O(n²) 的贪心算法通过. 我们可以加一个limit 来判断这个截止期限已经不行了,所以以后 ...

  6. [CSP-S 2019]括号树

    [CSP-S 2019]括号树 源代码: #include<cstdio> #include<cctype> #include<vector> inline int ...

  7. SDSC2019【游记】

    目录 SDSC2019 游记 Day0 Day 1 Day2 Day3 Day4 Day5 Day6 Day 7 Day8 SDSC2019 游记 Day0 这次夏令营在日照某大学举行,我很想夸一夸喷 ...

  8. ES6 展开运算符 三个点实际功能

    1.数组中使用let defaultColors = ['red', 'greed'] let favoriteColors = ['orange', 'yellow'] let fallColors ...

  9. mysql 过滤分组

    mysql> select * from table1; +----------+------------+-----+---------------------+ | name_new | t ...

  10. python在windows上创建虚拟环境

    cmd进入 安装virtualenvwrapper-win pip install virtualenvwrapper-win 创建名为pyve的虚拟环境 mkvirtualenv pyve 退出虚拟 ...