二叉树、栈、队列、链表的Java代码实现
这是我的学习总结。
如有文章存在谬误,欢迎指出,有其他意见或者建议,也欢迎留言
二叉树链表
前序遍历:先访问根节点,然后访问左子树、右子树
中序遍历:先访问左子树,然后访问根节点、右子树
后序遍历:先访问左子树、右子树,然后访问根节点
二叉树
/**
* 二叉树
*
* @author ChenSS 2016/11/10
* @version 1.0
*/
public class BinaryTree {
// 根节点数据
int data;
// 左子树
BinaryTree left;
// 右子树
BinaryTree right;
public BinaryTree(int data) {
this.data = data;
left = null;
right = null;
}
/**
* 插入新的节点,以根节点为准,大的放右边,小的放左边
*
* @param root
* 根节点
* @param data
* 数据
*/
public void insert(BinaryTree root, int data) {
if (data > root.data) {
if (root.right == null) {
root.right = new BinaryTree(data);
} else {
this.insert(root.right, data);
}
} else {
if (root.left == null) {
root.left = new BinaryTree(data);
} else {
this.insert(root.left, data);
}
}
}
}
二叉树遍历:
/**
* 二叉树遍历
*
* @author ChenSS 2016/11/10
* @version 1.0
*/
public class BinaryTreePreorder {
/**
* 先根遍历,优先输出根节点的值,然后遍历左子树,左子树为空,就遍历右子树
* 假设左子树不为空,输出左子树的根节点,继续对左子树的左右子树相同判断
*/
public static void preOrder(BinaryTree root) {
if (root == null)
return;
System.out.print(root.data + "-");
preOrder(root.left);
preOrder(root.right);
}
/**
* 中根遍历
*/
public static void inOrder(BinaryTree root) {
if (root == null)
return;
inOrder(root.left);
System.out.print(root.data + "-");
inOrder(root.right);
}
/**
* 后根遍历
*/
public static void postOrder(BinaryTree root) {
if (root == null)
return;
postOrder(root.left);
postOrder(root.right);
System.out.print(root.data + "-");
}
public static void main(String[] str) {
int[] array = { 12, 76, 35, 22, 16, 48, 90, 46, 9, 40 };
BinaryTree root = new BinaryTree(array[0]);
for (int i = 1; i < array.length; i++) {
root.insert(root, array[i]); // 向二叉树中插入数据
}
System.out.println("先根遍历:");
preOrder(root);
System.out.println();
System.out.println("中根遍历:");
inOrder(root);
System.out.println();
System.out.println("后根遍历:");
postOrder(root);
}
}
生成的二叉树如上,先序遍历的输出情况为:
12-9-76-35-22-16-48-46-40-90
如图:
1. 第一个根节点是12,打印12.
2. 12有左子树和右子树,先遍历左子树,左子树根节点是9,打印9.
3. 9没有子树,所以会去判断12的右子树,右子树的根节点是76,打印76.
4. 76左右子树都有,先遍历左子树,左子树的根节点是35,打印35.
打印22……
打印16……
5. 35的左子树遍历完了,遍历右子树,打印48……
栈
栈(Stack)是限制仅在表的一端进行插入和删除运算的线性表,是一种后进先出(LILO)的线性表。
栈的链表实现
/**
* 链表栈
*
* @author ChenSS 2016/11/10
* @version 1.0
*/
public class LinkedStack implements AbsStack {
private int count;
private Node top;
@Override
public void push(Object element) {
Node node = new Node(element);
node.setNext(top);
top = node;
count++;
}
@Override
public Object pop() {
if (isEmpty())
throw new NullPointerException("stack is null");
Object result = top.getElement();
top = top.getNext();
count--;
return result;
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public int size() {
return count;
}
@Override
public Object peek() {
Object result = top.getElement();
return result;
}
/**
* 链表,每一个对象拥有下一个对象的引用
*
* @author ChenSS
*
*/
private class Node {
// 链表元素
private Object element;
// 指向下一个元素的指针(引用)
private Node next;
public Node(Object element) {
this.element = element;
}
public void setNext(Node top) {
this.next = top;
}
public Node getNext() {
return next;
}
public Object getElement() {
return element;
}
}
public static void main(String[] args) {
LinkedStack stack = new LinkedStack();
// 压栈10次
for (int i = 0; i < 10; i++) {
stack.push(i);
}
// 出栈5次
System.out.println("连续执行5次出栈操作");
for (int i = 0; i < 5; i++) {
System.out.println(stack.pop());
}
System.out.println("栈是否为空: " + stack.isEmpty());
System.out.println("栈的大小为: " + stack.size());
System.out.println("栈顶元素为: " + stack.peek());
}
}
栈的数组实现
/**
* 数组栈
*
* @author ChenSS 2016/11/10
* @version 1.0
*/
public class ArrayStack implements AbsStack {
// 初始化一部分空间
private Object[] objs = new Object[16];
private int size = 0;
public void clear() {
for (int i = 0; i < size; i++)
objs[size] = null;
size = 0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ArrayStack: [");
for (int i = 0; i < size; i++) {
sb.append(objs[i].toString());
if (i != size - 1) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
@Override
public void push(Object element) {
if (size >= objs.length) {
resize();
}
objs[size++] = element;
}
@Override
public Object pop() {
if (size == 0) {
return null;
}
return objs[--size];
}
@Override
public Object peek() {
return objs[size];
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public int size() {
return size;
}
/**
* 数组扩容,一次加5个
*/
private void resize() {
objs = Arrays.copyOf(objs, objs.length + 5);
}
public static void main(String[] args) {
ArrayStack stack = new ArrayStack();
// 压栈10次
for (int i = 0; i < 10; i++) {
stack.push(i);
}
// 出栈5次
System.out.println("连续执行5次出栈操作");
for (int i = 0; i < 5; i++) {
System.out.println(stack.pop());
}
System.out.println("栈是否为空: " + stack.isEmpty());
System.out.println("栈的大小为: " + stack.size());
System.out.println("栈顶元素为: " + stack.peek());
System.out.println("元素为: " + stack.toString());
}
}
队列
队尾入列队头出,采用的是一种先进先出(LILO)的方式进行数据处理
/**
* 队列
*
* @author ChenSS 2016/11/10
* @version 1.0
*/
public class Queue {
// 队列长度,由构造函数初始化
private int maxSize;
// 队列
private long[] queArray;
// 队头
private int front;
// 队尾
private int rear;
// 元素的个数
private int size;
public Queue(int s) {
maxSize = s;
queArray = new long[maxSize];
front = 0;
rear = -1;
size = 0;
}
// 进队列
public void add(long j) {
// 处理循环
if (rear == maxSize - 1)
rear = -1;
// 队尾指针加1,把值j加入队尾
queArray[++rear] = j;
size++;
}
// 取得队列的队头元素。
public long take() {
// 取值和修改队头指针
long temp = queArray[front++];
// 处理循环
if (front == maxSize)
front = 0;
size--;
return temp;
}
// 取得队列的队头元素。该运算与 remove()不同,后者要修改队头元素指针。
public long peek() {
return queArray[front];
}
public boolean isEmpty() {
return (size == 0);
}
// 判队列是否已满。若已满返回一个真值,否则返回一个假值。
public boolean isFull() {
return (size == maxSize);
}
// 返回队列的长度
public int size() {
return size;
}
public static void main(String[] args) {
// 队列有5个元素
Queue theQueue = new Queue(5);
// 添加4个元素
theQueue.add(10);
theQueue.add(20);
theQueue.add(30);
theQueue.add(40);
// 移除3个元素
theQueue.take();
theQueue.take();
theQueue.take();
// 添加4个元素
theQueue.add(50);
theQueue.add(60);
theQueue.add(70);
theQueue.add(80);
// 遍历队列并移除所有元素
while (!theQueue.isEmpty()) {
long n = theQueue.take();
System.out.print(n);
System.out.print(" ");
}
}
}
链表
单向链表
在表头插入一个新的链接点,每个元素有下一个元素的指针(索引),根据当前元素,可以获取下一个元素。
双端链表
与单向链表的不同之处在保存有对最后一个链接点的引用(last),实现了在链尾也可以插入数据的功能
双向链表
在过去的学习中,我们使用到了迭代器,迭代器有个向后遍历的功能,而双向链表,就增加了一个功能:往回遍历。每一个元素有两个指针,一个指向前一个元素,一个指向后一个元素。(参考:LinkedList对象)
LinkedList底层代码(LinkedList的元素):
每一个元素包含两个指针(引用),一个指向前面一个元素,一个指向后面一个元素,也就是说,我们只要能得到其中任何一个元素,就可以遍历整个链表。
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
LinkedList逆向遍历功能展示:
/**
* LinkedList测试
*
* @author ChenSS 2016/11/10
* @version 1.0
*/
public class BinaryTreePlus {
public static void main(String[] args) {
LinkedList<String> list=new LinkedList<>();
list.addFirst("AAA");
list.addLast("BBB");
ListIterator<String> iterator=list.listIterator(list.size());
while(iterator.hasPrevious()){
System.out.println(iterator.previous());
}
}
}
LinkedList代码实现:
/**
* 双向链表
*
* @author ChenSS 2016/11/10
* @version 1.0
*/
public class DoubleLists<T> {
private DNode<T> header;
private int listSize;
public DoubleLists() {
header = new DNode<T>();
listSize = 0;
}
private static class DNode<T> {
T nodeValue;
DNode<T> prev;
DNode<T> next;
public DNode() { // for header
nodeValue = null;
prev = this; // left
next = this; // right
}
public DNode(T item) {
nodeValue = item;
prev = this;
next = this;
}
}
public boolean isEmpty() {
return (header.prev == header || header.next == header);
}
public int size() {
return listSize;
}
private DNode<T> addBefore(DNode<T> curr, T item) {
DNode<T> newNode, prevNode;
newNode = new DNode<T>(item);
prevNode = curr.prev;
newNode.prev = prevNode;
newNode.next = curr;
prevNode.next = newNode;
curr.prev = newNode;
return newNode;
}
public boolean add(T item) {
addBefore(header, item);
listSize++;
return true;
}
public void addFirst(T item) {
addBefore(header.next, item);
listSize++;
}
public void addLast(T item) {
addBefore(header, item);
listSize++;
}
private void remove(DNode<T> curr) {
if (curr.next == curr)
return;
DNode<T> prevNode = curr.prev, nextNode = curr.next;
prevNode.next = nextNode;
nextNode.prev = prevNode;
}
public boolean remove(Object o) {
for (DNode<T> p = header.next; p != header; p = p.next) {
if (o.equals(p.nodeValue)) {
remove(p);
listSize--;
return true;
}
}
return false;
}
public void printList() {
for (DNode<T> p = header.next; p != header; p = p.next)
System.out.println(p.nodeValue);
}
private class MyIterator implements Iterator<T> {
public DNode<T> nextNode = header.next;
public DNode<T> lastReturned = header;
public boolean hasNext() {
return nextNode != header;
}
public T next() {
if (nextNode == header)
throw new NoSuchElementException("");
lastReturned = nextNode;
nextNode = nextNode.next;
return lastReturned.nodeValue;
}
public void remove() {
if (lastReturned == header)
throw new IllegalStateException("");
DoubleLists.this.remove(lastReturned);
lastReturned = header;
listSize--;
}
}
private class MyListIterator extends MyIterator implements ListIterator<T> {
private int nextIndex;
MyListIterator(int index) {
if (index < 0 || index > listSize)
throw new IndexOutOfBoundsException("");
if (index < (listSize >> 1)) {
nextNode = header.next;
for (nextIndex = 0; nextIndex < index; nextIndex++)
nextNode = nextNode.next;
} else {
nextNode = header;
for (nextIndex = listSize; nextIndex > index; nextIndex--)
nextNode = nextNode.prev;
}
}
public boolean hasPrevious() {
return nextIndex != 0;
// return nextNode.prev != header;
}
public T previous() {
if (nextIndex == 0)
throw new NoSuchElementException("no");
lastReturned = nextNode = nextNode.prev;
nextIndex--;
return lastReturned.nodeValue;
}
public void remove() {
if (lastReturned == header)
throw new IllegalStateException("");
DoubleLists.this.remove(lastReturned);
nextIndex--;
listSize--;
if (lastReturned == nextNode)
nextNode = nextNode.next;
lastReturned = header;
}
public void add(T item) {
DoubleLists.this.addBefore(nextNode, item);
nextIndex++;
listSize++;
lastReturned = header;
}
public void set(T item) {
if (lastReturned == header)
throw new IllegalStateException();
lastReturned.nodeValue = item;
}
public int nextIndex() {
return nextIndex;
}
public int previousIndex() {
return nextIndex - 1;
}
}
public Iterator<T> iterator() {
return new MyIterator();
}
public ListIterator<T> listIterator(int index) {
return new MyListIterator(index);
}
public static void main(String[] args) {
DoubleLists<String> t = new DoubleLists<String>();
t.add("A");
t.add("B");
t.remove("B");
t.addFirst("AA");
t.addLast("BB");
t.add("C");
t.add("D");
ListIterator<String> it = t.listIterator(t.size());
while (it.hasPrevious()) {
//指向位置前面的元素
System.out.println(it.previous());
}
}
}
4种常见的排序
/**
* 排序算法
*
* @author ChenSS 2016/11/10
* @version 1.0
*/
public class SortUtil {
/**
* 选择排序,采用记角标的方式,记住数组中最小的那个数的角标,然后与开始的元素交换位置
*/
public static void selectSort(int[] a) {
int index;
int temp;
for (int i = 0; i < a.length - 1; i++) {
index = i;
for (int j = i + 1; j < a.length; j++) {
if (a[index] > a[j])
index = j;
}
if (index != i) {
temp = a[index];
a[index] = a[i];
a[i] = temp;
}
}
}
/**
* 快速排序,以一个数为基准(通常选第一个数),大数置于右边,小数置于左边,
* 此后以相同的算法对左边和右边这两组数进行排序,以此类推,
* 直至整个数组从小到大排列
*/
public static void quickSort(int[] a, int left, int right) {
if (left >= right)
return;
int temp = a[left];
int low = left;
int high = right;
while (low < high) {
while (low < high && a[high] >= temp)
high--;
a[low] = a[high];
while (low < high && a[low] <= temp)
low++;
a[high] = a[low];
}
a[low] = temp;
quickSort(a, left, low - 1);
quickSort(a, low + 1, right);
}
/**
* 冒泡排序
*/
public static void bubbleSort(int[] a) {
int temp;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a.length - i - 1; j++) {
if (a[j] > a[j + 1]) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
/**
* 插入排序,和选择排序类似,遍历取出最小的那个数,然后插入到第一个元素的位置,其它元素全部后移
*/
public static void insertSort(int a[]) {
for (int i = 1; i < a.length; i++) {
int key = a[i];
int index = i;
while (index > 0 && a[index - 1] > key) {
a[index] = a[index - 1];
index--;
}
a[index] = key;
}
}
/**
* 测试方法
*/
public static void print(int a[]) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int[] arr = { 7, 6, 5, 4, 2, 3, 9, 90, 4, 50 };
insertSort(arr);
print(arr);
}
}
二叉树、栈、队列、链表的Java代码实现的更多相关文章
- 单链表反转java代码
据说单链表反转问题面试中经常问,而链表这个东西相对于数组的确稍微难想象,因此今天纪录一下单链表反转的代码. 1,先定义一个节点类. public class Node { int index; Nod ...
- 二叉树的层次遍历(Java代码实现)
与树的前中后序遍历的DFS思想不同,层次遍历用到的是BFS思想.一般DFS用递归去实现(也可以用栈实现),BFS需要用队列去实现. 层次遍历的步骤是: 1.对于不为空的结点,先把该结点加入到队列中 2 ...
- 4、链栈的实现(java代码)
1.链节点 public class Node<T> { public T data; public Node next; } 2.实现代码 public class Stack<T ...
- java代码实现队列的优化
package com.voole.queun; /** * @Decription 队列 * @author TMAC-J * */ public class Queun { /** * 初始化队列 ...
- 数据结构之链表及其Java实现
数据的存储一般分线性存储结构和链式存储结构两种.前者是一种顺序的存储方式,在内存中用一块连续的内存空间存储数据,即逻辑上相连的物理位置相邻,比较常见的就是数组:后者是一种链式存储方式,不保证顺序性,逻 ...
- java面向对象的栈 队列 优先级队列的比较
栈 队列 有序队列数据结构的生命周期比那些数据库类型的结构(比如链表,树)要短得多.在程序操作执行期间他们才被创建,通常用他们去执行某项特殊的任务:当完成任务之后,他们就会被销毁.这三个数据结构还有一 ...
- java 集合 Connection 栈 队列 及一些常用
集合家族图 ---|Collection: 单列集合 ---|List: 有存储顺序 , 可重复 ---|ArrayList: 数组实现 , 查找快 , 增删慢 ---|LinkedList: 链表实 ...
- Java 容器之 Connection栈队列及一些常用
集合家族图 ---|Collection: 单列集合 ---|List: 有存储顺序 , 可重复 ---|ArrayList: 数组实现 , 查找快 , 增删慢 ---|LinkedList: 链表实 ...
- java 栈和队列的模拟--java
栈的定义:栈是一种特殊的表这种表只在表头进行插入和删除操作.因此,表头对于栈来说具有特殊的意义,称为栈顶.相应地,表尾称为栈底.不含任何元素的栈称为空栈. 栈的逻辑结构:假设一个栈S中的元素为an,a ...
随机推荐
- Unity Shader - 消融效果原理与变体
基本原理与实现 主要使用噪声和透明度测试,从噪声图中读取某个通道的值,然后使用该值进行透明度测试. 主要代码如下: fixed cutout = tex2D(_NoiseTex, i.uvNoiseT ...
- jQuery在项目中的应用
版权声明:本文为博主原创文章,未经博主允许不得转载.(转载需注明出处 http://www.cnblogs.com/yanfei1819/p/7743661.html) [摘要] 最近在项目中应用 ...
- LeetCode 414. Third Maximum Number (第三大的数)
Given a non-empty array of integers, return the third maximum number in this array. If it does not e ...
- LeetCode 59. Spiral Matrix II (螺旋矩阵之二)
Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order. For ...
- CNCC2017梳理
大牛云集的中国计算机大会:大会日程表:http://cncc.ccf.org.cn/cn/news/schedule_empty 早上的论坛可以在爱奇艺下载视频 下午的分论坛是多个同时进行的,我也只去 ...
- iOS之 Category 属性 的理解
在 Objective-C 中可以通过 Category 给一个现有的类添加属性,但是却不能添加实例变量 反正读第一遍的时候我是有点晕的,可以添加“属性”,然后又说“添加实例变量”,第一感觉就好像 有 ...
- Ubuntu配置OpenStack 二:配置时间同步NTP和安装数据库Maridb以及问题总结
继上一节Ubuntu配置OpenStack 一:配置主机环境,下面继续为安装时间同步,以及配置openstack的安装包源和安装数据库Maridb.(全文截图都是由自己徒手搭建完成并且截图) 一.安装 ...
- c++学习笔记---04---从另一个小程序接着说
从另一个小程序接着说 文件I/O 前边我们已经给大家简单介绍和演示过C和C++在终端I/O处理上的异同点. 现在我们接着来研究文件I/O. 编程任务:编写一个文件复制程序,功能实现将一个文件复制到另一 ...
- 蓝桥杯-算法训练--ALGO-6 安慰奶牛
问题描述Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路.道路被用来连接N个牧场,牧场被连续地编号为1到N.每一个牧场都是一个奶牛的家.FJ计划除去P条道路中尽可能多的道路,但 ...
- 【Kafka源码】ReplicaManager启动过程
在KafkaServer启动过程的入口中,会启动Replica Manager,众所周知,这是一个副本管理器.replica在Kafka中扮演的角色很重要,是保证消息不丢失的一个重要概念. repli ...