学习数据结构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结束之后,我们很快就要迎来更加丧心病狂的省选了-_-|| 所以从写完上一篇博客开始到现在我一直深陷数据结构和网络流的漩涡不能自拔 今天终于想起来写博客(只是懒吧.. ...
随机推荐
- tf.logging.set_verbosity
tf.logging.set_verbosity (tf.logging.INFO) 作用:将 TensorFlow 日志信息输出到屏幕
- c++合并两个序列函数merge()和inplace_merge()
大家在写归并排序时是不是觉得合并两个序列有点麻烦,有快速的方法吗? 我们全部函数自己写,比如: #include<bits/stdc++.h> using namespace std; # ...
- python基础知识总结大全(转载)
- java 练习(公司年销售额求和)
/*B:公司年销售额求和 某公司按照季度和月份统计的数据如下:单位(万元) 第一季度:22,66,44 第二季度:77,33,88 第三季度:25,45,65 第四季度:11,66,99 */ int ...
- 开源项目 05 Dapper
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- 洛谷 P1629 邮递员送信 题解
P1629 邮递员送信 题目描述 有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N.由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要 ...
- 18年今日头条笔试第一题题解:球迷(fans)
其实本题是加强版,原数据是100*100的,老师为了尊重我们的智商加成了3000*3000并进行了字符串处理…… 上原题~ 球迷 [问题描述] 一个球场C的球迷看台可容纳M*N个球迷.官方想统计一共有 ...
- ICEM-R-b
原视频下载地址:https://pan.baidu.com/s/1i4JGk8d ;密码: 4xr2
- go 练习:HTTP 处理
这篇文章只是联系go指南时的笔记吧. package main import ( "fmt" "log" "net/http" ) type ...
- 从阿里云DATAV GeoAtlas接口抽取行政区划数据
阿里云提供的地理信息接口 https://datav.aliyun.com/tools/atlas/ 有两个接口, 一个是[行政编码].json, 一个是[行政编码]_full.json, 从接口中可 ...