学习数据结构Day4
链表
之前看过了动态数组,栈和队列,虽然我们把第一个叫做动态数组,但是,他们的底层实质上还是静态数组。靠
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的更多相关文章
- Spark菜鸟学习营Day4 单元测试程序的编写
Spark菜鸟学习营Day4 单元测试程序的编写 Spark相比于传统代码是比较难以调试的,单元测试的编写是非常必要的. Step0:需求分析 在测试案例编写前,需完成需求分析工作,明确程序所有的输入 ...
- SqList *L 和 SqList * &L的区别/学习数据结构突然发现不太懂 小祥我查找总结了一下
小祥在学习李春葆的数据结构教程时发现一个小问题,建立顺序表和输出线性表,这两个函数的形参是不一样的. 代码在这里↓↓↓ //定义顺序表L的结构体 typedef struct { Elemtype d ...
- 在Object-C中学习数据结构与算法之排序算法
笔者在学习数据结构与算法时,尝试着将排序算法以动画的形式呈现出来更加方便理解记忆,本文配合Demo 在Object-C中学习数据结构与算法之排序算法阅读更佳. 目录 选择排序 冒泡排序 插入排序 快速 ...
- OpenCV图像处理学习笔记-Day4(完结)
OpenCV图像处理学习笔记-Day4(完结) 第41课:使用OpenCV统计直方图 第42课:绘制OpenCV统计直方图 pass 第43课:使用掩膜的直方图 第44课:掩膜原理及演示 第45课:直 ...
- 数据结构之Queue | 让我们一块来学习数据结构
前面的两篇文章分别介绍了List和Stack,下面让我们一起来学习Queue 数据结构之List | 让我们一块来学习数据结构 数据结构之Stack | 让我们一块来学习数据结构 队列的概况 队列是一 ...
- 数据结构之LinkedList | 让我们一块来学习数据结构
highlight: monokai theme: vue-pro 上一篇文章中使用列表(List)对数据排序,当时底层储存数据的数据结构是数组.本文将讨论另外一种列表:链表.我们会解释为什么有时链表 ...
- 数据结构之Set | 让我们一块来学习数据结构
数组(列表).栈.队列和链表这些顺序数据结构对你来说应该不陌生了.现在我们要学习集合,这是一种不允许值重复的顺序数据结构.我们将要学到如何创建集合这种数据结构,如何添加和移除值,如何搜索值是否存在.你 ...
- MySQL 学习 --- 数据结构和索引
本文参考了多篇文章集成的笔记,希望各位学习之前可以阅读以下参考资料先 概述 文章分几个部分 :第一部分介绍了B-Tree 和 B+Tree 这种数据结构作为索引:第二部分介绍索引的最左前缀原则和覆盖索 ...
- 省选算法学习-数据结构-splay
于是乎,在丧心病狂的noip2017结束之后,我们很快就要迎来更加丧心病狂的省选了-_-|| 所以从写完上一篇博客开始到现在我一直深陷数据结构和网络流的漩涡不能自拔 今天终于想起来写博客(只是懒吧.. ...
随机推荐
- Browsersync 省时浏览器同步测试工具,浏览器自动刷新,多终端同步
官网地址 http://www.browsersync.cn/ 1.安装 BrowserSync npm install -g browser-sync 2.启动 BrowserSync // --f ...
- django-发送文件
客户端授权密码”,勾选“开启”,弹出新窗口填写手机验证码. settings.py配置 EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBac ...
- c语言的可变参数实例
可变参数函数实现的步骤如下: 1.在函数中创建一个va_list类型变量 2.使用va_start对其进行初始化 3.使用va_arg访问参数值 4.使用va_end完成清理工作 接下来我们来实现一个 ...
- 10-Flutter移动电商实战-使用FlutterSwiper制作轮播效果
1.引入flutter_swiper插件 flutter最强大的siwiper, 多种布局方式,无限轮播,Android和IOS双端适配. 好牛X得介绍,一般敢用“最”的一般都是神级大神,看到这个介绍 ...
- LeetCode 1046. Last Stone Weight
原题链接在这里:https://leetcode.com/problems/last-stone-weight/ 题目: We have a collection of rocks, each roc ...
- CI持续集成 -- git 与 gitlab
版本控制系统概述 git Git基本概述 Git是一个免费的开源分布式版本控制系统,旨在快速高效地处理从小型到大型项目的所有内容. Git安装配置 #安装Git yum install -y git ...
- S1_搭建分布式OpenStack集群_04 keystone认证服务安装配置
一.新建数据库及用户(控制节点)# mysql -uroot -p12345678MariaDB [(none)]> CREATE DATABASE keystone;MariaDB [(non ...
- BZOJ 1213: [HNOI2004]高精度开根
二次联通门 : BZOJ 1213: [HNOI2004]高精度开根 正解 NTT+高精+倍增+二分 但是可以用python 2333333 m,n=int(raw_input()),int(raw_ ...
- Cocos Creator 功能介绍
cc.Class({ extends: cc.Component, properties: { anim: cc.Animation }, playRun: function() { this.ani ...
- 【POJ1573】Robot Motion
题目传送门 本题知识点:模拟 本题的题意也很简单. 给出一个矩阵,矩阵里面有着东南西北(上下左右)的指示,当机器人走到上面时则会按照指示前进.机器人每次都从最上面一行的某一列进入. 需要判断的是机器人 ...