一、 堆
1 入堆
private java.util.ArrayList<E> list = new java.util.ArrayList<E>();
public void add(E newObject){
list.add(newObject);
int currentIndex = list.size() - 1;
while(currentIndex > 0){
int parentIndex = (currentIndex - 1) / 2;
if(list.get(currentIndex).compareTo(list.get(parentIndex)) > 0){
E tmp = list.get(currentIndex);
list.set(currentIndex,list.get(parentIndex));
list.set(parentIndex, tmp);
}
else
break;
currentIndex = parentIndex;
}
}
2出堆
private java.util.ArrayList<E> list = new java.util.ArrayList<E>();
public E remove(){
if(list.size() == 0) return null;
E removeObject = list.get(0);
list.set(0,list.get(list.size() - 1));
list.remove(list.size() - 1);
int currentIndex = 0;
while(currentIndex < list.size()){
int leftChildIndex = 2 * currentIndex + 1;
int rightChildIndex = 2 * currentIndex + 2;
if(leftChildIndex >= list.size()) break;
int maxChildIndex = leftChildIndex;
if(rightChildIndex < list.size()){
if(list.get(maxChildIndex).compareTo(list.get(rightChildIndex)) < 0){
maxChildIndex = rightChildIndex;
}
}
if(list.get(currentIndex).compareTo(list.get(maxChildIndex)) < 0){
E tmp = list.get(currentIndex);
list.set(currentIndex,list.get(maxChildIndex));
list.set(maxChildIndex,tmp);
}
else
break;
}
return removeObject;
}
二、二叉树
二叉树的插入,搜索和删除(针对搜索二叉树BFS:二叉查找树(左子树都小于根节点的值,右子树都大于根节点的值,元素不重复))
先定义一个二叉树的结点
class TreeNode<E> {
E element;
TreeNode<E> left;
TreeNode<E> right;
public TreeNode(E e) {
element = e;
}
}
再定义一个类变量
protected TreeNode<E> root;
protected int size = 0;
插入
public boolean insert(E e){
TreeNode<E> parent = null;
TreeNode<E> current = root;
if(current == null){
current = new TreeNode<E>(e);
return true;
}
while(current != null) {
if(e.compareTo(current.element) < 0) {
parent = current;
current = current.left;
}
if(e.compareTo(current.element) > 0) {
parent = current;
current = current.left;
}
else
return false;
}
if(e.compareTo(parent.element) < 0)
parent.left = new TreeNode<E>(e);
else
parent.right = new TreeNode<E>(e);
return true;
}
二叉树的删除
二叉树的删除较为复杂。主要是分两种情况考虑:要删除的结点(current)是否存在左子树。
若current.left == null;只需要让Current = current.right;current可能是父节点的左子树,也可能是右子树。这要分两种情况考虑。
若current.left != null;只需要让current.left的子节点中,最大的数取代current中的元素,让后将current.left子结点中,该元素的结点删除即可。这种其实也分为两种情况:
1 current.left.right == null ;2current.left.right != null;
public boolean delete(E e) {
TreeNode<E> parent = null;
TreeNode<E> current = root;
while(current != null){
if(e.compareTo(current.element) < 0) {
parent = current;
current = current.left;
}
if(e.compareTo(current.element) > 0) {
parent = current;
current = current.right;
}
else
break;
}
if(current == null)
return false;
//case1:current has no left children
if(current.left == null){
if(parent == null) {
root = current.right;
}
else {
if (e.compareTo(parent.element) < 0)
parent.left = current.right;
else
parent.right = current.right;
}
}
else {
//case2: The current node has a left child
TreeNode<E> parentOfRightMost = current;
TreeNode<E> rightMost = current.left;
while(rightMost.right != null) {
parentOfRightMost = rightMost;
rightMost = rightMost.right;
}
current.element = rightMost.element;
if (parentOfRightMost.right == rightMost)
parentOfRightMost.right = rightMost.left;
else
parentOfRightMost.left = rightMost.left;
}
size- -;
return true;
}
二叉树的搜索:
public boolean search(E e) {
TreeNode<E> current = root;
while(current != null) {
if (e.compareTo(current.element) < 0)
current = current.left;
else if (e.compareTo(current.element) > 0)
current = current.right;
else
return true;
}
return false;
}
二叉树的遍历:前根遍历 中根遍历 后跟遍历 深度优先 广度优先 S型遍历
中根遍历(递增方式显示所有节点)
public void inorder() {
inorder(root);
}
protected void inorder(TreeNode<E> root){
if(root == null)
return ;
inorder(root.left);
System.out.print(root.element + " ");
inorder(root.right);
}
前根遍历(深度优先与此相同)
public void preorder() {
preorder(root);
}
protected void preorder(TreeNode<E> root){
if(root == null)
return ;
System.out.print(root.element + " ");
preorder(root.left);
preorder(root.right);
}
其实深度优先遍历还有另外一种方式,先遍历右子树,压入栈,再遍历左子树,压入栈,最后遍历根,压入栈
public void dfs(TreeNode<E> root) {
java.util.Stack<TreeNode<E>> stack =
new java.util.Stack<TreeNode<E>>();
stack.push(root);
while(stack.isEmpty()) {
TreeNode<E> temp = stack.pop();
System.out.println(temp.element);
if(temp.right != null)
stack.push(temp.right);
if(temp.left != null)
stack.push(temp.left);
}
}
二叉树后跟遍历:(可以找出一个文件系统中目录的个数,每个目录是一个内部结点,每个文件是一个叶子几点(个人认为这句话默认是没有空目录))
public void posorder() {
posorder(root);
}
protected void posorder(TreeNode<E> root){
if(root == null)
return ;
posorder(root.left);
posorder(root.right);
System.out.print(root.element + " ");
}
BFS:广度优先遍历(层次遍历)
public void bfs(TreeNode<E> root) {
java.util.Queue<TreeNode<E>> queue1 =
new java.util.LinkedList<TreeNode<E>>();
java.util.Queue<TreeNode<E>> queue2 =
new java.util.LinkedList<TreeNode<E>>();
queue1.offer(root);
while(queue1.isEmpty() || queue2.isEmpty()) {
if(queue2.isEmpty()){
while(!queue1.isEmpty()){
TreeNode<E> temp = queue1.poll();
if(temp.left != null)
queue2.offer(temp.left);
if(temp.right != null)
queue2.offer(temp.right);
System.out.print(temp.element + " ");
}
}
else {
while(!queue2.isEmpty()){
TreeNode<E> temp = queue2.poll();
if(temp.left != null)
queue1.offer(temp.left);
if(temp.right != null)
queue1.offer(temp.right);
System.out.print(temp.element + " ");
}
}
System.out.println();
}
}
s型遍历
S型层序遍历,就是把上面使用的queue换为stack,注意左右子节点添加顺序,就可以了
public void S_LevelOrderPrint(){
Stack<Node<E>> stack1 = new Stack<Node<E>>();
Stack<Node<E>> stack2 = new Stack<Node<E>>();
stack1.add(this);
while(!stack1.isEmpty() || !stack2.isEmpty()){
if(stack1.isEmpty()){
while(!stack2.isEmpty()){
Node<E> currentNode = stack2.pop();
System.out.print(currentNode.value + " ");
if(currentNode.left != null)
stack1.push(currentNode.left);
if(currentNode.right != null)
stack1.push(currentNode.right);
}
}else{
while(!stack1.isEmpty()){
Node<E> currentNode = stack1.pop();
System.out.print(currentNode.value + " ");
if(currentNode.right != null)
stack2.add(currentNode.right);
if(currentNode.left != null)
stack2.add(currentNode.left);
}
}
System.out.println();
}
}
三、图(Graph)的深度优先和广度优先
图的输入
顶点:数组,元素可以是字符串或线性表,元素可以是顶点对象
边:可以是边数组,例如{{u1,v1},...,{un,vn}},也可以是线性表,里面放边的对象。
图的存储
顶点:线性表 List<T>
边:线性表List<ArrayList<Integer>> 或者List<ArrayList<Edger>>.Edge为边的对象。
图的表示(输出)
邻接矩阵或邻接线性表List<ArrayList<Integer>>
备注:上面的任何形式都可以表示图,这样写方便掌握程序数据构造。
import java.util.*;
public class ExerciseGraphDFSAndBFS<T> {
private List<T> vertices;
private List<ArrayList<Edge>> neighbors;
public ExerciseGraphDFSAndBFS(int[][] edges, T[] vertices ) {
this.vertices = new ArrayList<T>();
neighbors = new ArrayList<ArrayList<Edge>>();
int numberOfVertices = vertices.length;
for(int i = 0; i < numberOfVertices; i++)
this.vertices.add(vertices[i]);
for(int i = 0; i < numberOfVertices; i++)
neighbors.add(new ArrayList<Edge>());
for(int i = 0; i < edges.length; i++) {
int u = edges[i][0];
int v = edges[i][1];
neighbors.get(u).add(new Edge(u, v));
}
}
public void getGraphDFS(int v) {
int numberOfVertices = vertices.size();
boolean[] isVisited = new boolean[numberOfVertices];
List<T> searchOrders = new ArrayList<T>();
getGraphDFS(v, isVisited, searchOrders);
System.out.println(searchOrders);
}
private void getGraphDFS(int v, boolean[] isVisited,
List<T> searchOrders) {
searchOrders.add(vertices.get(v));
isVisited[v] = true;
for(Edge u: neighbors.get(v)) {
if(!isVisited[u.v]) {
getGraphDFS(u.v, isVisited,
searchOrders);
}
}
}
public void getGraphBFS(int v) {
List<T> searchOrders = new ArrayList<T>();
boolean[] isVisited = new boolean[vertices.size()];
Queue<Integer> queue = new LinkedList<Integer>();
isVisited[v] = true;
queue.offer(v);
while(!queue.isEmpty()) {
int u = queue.poll();
searchOrders.add(vertices.get(u));
for(Edge e : neighbors.get(u)) {
if(!isVisited[e.v]) {
queue.offer(e.v);
isVisited[e.v] = true;
}
}
}
System.out.println(searchOrders);
}
class Edge {
private int u;
private int v;
public Edge(int u, int v){
this.u = u;
this.v = v;
}
}
}
测试程序
public class ExerciseTestDFS {
public static void main(String[] args) {
String[] vertices = {"Seattle", "San Francisco", "Los Angeles",
"Dever", "Kansas City", "Chicago", "Boston", "New York",
"Atlanta", "Miami", "Dallas", "Houston" };
int[][] edges = {
{0, 1}, {0, 3}, {0, 5},
{1, 0}, {1, 2}, {1, 3},
{2, 1}, {2, 3}, {2, 4}, {2, 10},
{2, 0}, {3, 1}, {3, 2}, {3, 4}, {3, 5},
{4, 2}, {4, 3}, {4, 5}, {4, 7}, {4, 8}, {4, 10},
{5, 0}, {5, 3}, {5, 4}, {5, 6}, {5, 7},
{6, 5}, {6, 7},
{7, 4}, {7, 5}, {7, 6}, {7, 8},
{8, 4}, {8, 7}, {8, 9}, {8, 10}, {8, 11},
{9, 8}, {9, 11},
{10, 2}, {10, 4}, {10, 8}, {10, 11},
{11, 8}, {11, 9}, {11, 10}
};
ExerciseGraphDFSAndBFS<String> graph1 = new
ExerciseGraphDFSAndBFS<String>(edges, vertices);
graph1.getGraphDFS(5);
graph1.getGraphBFS(5);
}
}
四、加权图的最小生成树(MST)和最短路径
知识记忆:
加权图的输入
顶点:数组,里面的元素可以是字符或者对象(顶点高级表示),也可以是线性表
边:可以是边数组{{u1,v1,w1},....{un,vn,wn}},也可以是线性表,里面放边的对象.
加权图的数据存储
顶点:线性表,List<T>
边:优先链接线性表 List<PriotityQueue<WeightedEdge>>。
加权图的表示形式(输出)
加权邻接矩阵。
备注:上面的任何形式都可以表示加权图,这样写方便掌握程序数据构造。
算法程序:
import java.util.*;
public class ExerciseMSTAndShortestPath<T> {
private List<PriorityQueue<WeightedEdge1>> queues;
private List<T> vertices;
public ExerciseMSTAndShortestPath(T[] vertices, int[][] edges){
queues = new ArrayList<PriorityQueue<WeightedEdge1>>();
this.vertices = new ArrayList<T>();
for(int i = 0; i < vertices.length; i++) {
queues.add(new PriorityQueue<WeightedEdge1>());
this.vertices.add(vertices[i]);
}
for(int i = 0; i < edges.length; i++){
int u = edges[i][0];
int v = edges[i][1];
int w = edges[i][2];
queues.get(u).offer(new WeightedEdge1(u, v, w));
}
}
public void getMST(int verticesIndex) {
int numberOfVertices = vertices.size();
int[] parent = new int[numberOfVertices];
for(int i = 0; i < numberOfVertices; i++)
parent[i] = -1;
List<Integer> T = new ArrayList<Integer>();
T.add(verticesIndex);
int totalWeight = 0;
List<PriorityQueue<WeightedEdge1>> queues = deepClone(this.queues);
while(T.size() < numberOfVertices) {
double minWeight = Double.MAX_VALUE;
int v = -1;
for(int u : T){
while(!queues.get(u).isEmpty() &&
T.contains(queues.get(u).peek().v))
queues.get(u).remove();
if(queues.get(u).isEmpty())
continue;
WeightedEdge1 edge = queues.get(u).peek();
if(edge.w < minWeight) {
v = edge.v;
minWeight = edge.w;
parent[v] = u;
}
}
totalWeight += minWeight;
T.add(v);
}
System.out.println("The start index is:" +
vertices.get(verticesIndex));
System.out.println("The total weight is:" +
totalWeight);
System.out.println("The MST is:");
for(int i = 0; i < parent.length; i++ ){
if(parent[i] != -1){
System.out.print("(" + vertices.get(parent[i])
+ ", " + vertices.get(i) + ") ");
}
}
System.out.println();
}
private List<PriorityQueue<WeightedEdge1>> deepClone(
List<PriorityQueue<WeightedEdge1>> queues){
List<PriorityQueue<WeightedEdge1>> copiedQueue =
new ArrayList<PriorityQueue<WeightedEdge1>>();
for(int i = 0; i < queues.size(); i++){
copiedQueue.add(new PriorityQueue<WeightedEdge1>());
for(WeightedEdge1 e: queues.get(i))
copiedQueue.get(i).offer(e);
}
return copiedQueue;
}
public void getShortestPath(int startIndex) {
List<Integer> T = new ArrayList<Integer>();
int numberOfVertices = vertices.size();
int[] parent = new int[numberOfVertices];
int[] costs = new int[numberOfVertices];
parent[startIndex] = -1;
costs[startIndex] = 0;
T.add(startIndex);
List<PriorityQueue<WeightedEdge1>> queues =
deepClone(this.queues);
while(T.size() < numberOfVertices) {
int smallestCost = Integer.MAX_VALUE;
int v = -1;
for(int u: T) {
while(!queues.get(u).isEmpty() &&
T.contains(queues.get(u).peek().v)) {
queues.get(u).remove();
}
if(queues.get(u).isEmpty())
continue;
WeightedEdge1 edge = queues.get(u).peek();
if(costs[u] + edge.w < smallestCost) {
v = edge.v;
smallestCost = costs[u] + edge.w;
parent[v] = u;
}
}
T.add(v);
costs[v] = smallestCost;
}
System.out.println();
int index = startIndex;
for(int i = 0; i < numberOfVertices; i++){
List<T> path = new ArrayList<T>();
index = i;
while(index != -1) {
path.add(vertices.get(index));
index = parent[index];
}
System.out.print("Path from " + path.get(path.size() - 1) +
" to " + path.get(0) + " is:");
for(int j = path.size() - 1; j >= 0; j--)
System.out.print(path.get(j) + " ");
System.out.println();
}
}
public static class WeightedEdge1 implements Comparable<WeightedEdge1>{
int u;
int v;
int w;
public WeightedEdge1(int u, int v, int w){
this.u = u;
this.v = v;
this.w = w;
}
public int compareTo(WeightedEdge1 o){
return w - o.w;
}
}
}
测试程序:
public class TestShortestPath {
public static void main(String[] args) {
String[] vertices = {"Seattle", "San Francisco", "Los Angeles",
"Denver", "Kansas City", "Chicago", "Boston", "New York",
"Atlanta", "Miami", "Dallas", "Houston"};
int[][] edges = {
{0, 1, 807}, {0, 3, 1331}, {0, 5, 2097},
{1, 0, 807}, {1, 2, 381}, {1, 3, 1267},
{2, 1, 381}, {2, 3, 1015}, {2, 4, 1663}, {2, 10, 1435},
{3, 0, 1331}, {3, 1, 1267}, {3, 2, 1015}, {3, 4, 599},
{3, 5, 1003},
{4, 2, 1663}, {4, 3, 599}, {4, 5, 533}, {4, 7, 1260},
{4, 8, 864}, {4, 10, 496},
{5, 0, 2097}, {5, 3, 1003}, {5, 4, 533},
{5, 6, 983}, {5, 7, 787},
{6, 5, 983}, {6, 7, 214},
{7, 4, 1260}, {7, 5, 787}, {7, 6, 214}, {7, 8, 888},
{8, 4, 864}, {8, 7, 888}, {8, 9, 661},
{8, 10, 781}, {8, 11, 810},
{9, 8, 661}, {9, 11, 1187},
{10, 3, 1435}, {10, 4, 496}, {10, 8, 781}, {10, 11, 239},
{11, 8, 810}, {11, 9, 1187}, {11, 10, 239}
};
ExerciseMSTAndShortestPath<String> graph2 =
new ExerciseMSTAndShortestPath<String>(vertices, edges);
graph2.getMST(0);
graph2.getShortestPath(0);
}
}