数据结构中的一些算法

一、 堆

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);
		}
}









 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值