版权声明:欢迎转载,但请注明出处! https://blog.csdn.net/DavidHuang2017/article/details/88034446
一、单链表
1.结点定义
public class ListNode {
int data;
ListNode next;
ListNode (int data){
this.data=data;
}
}
2.建立链表
/**
* 头插法建立链表
* @return 链表指针
*/
public ListNode createLsit1(){
ListNode L=null,s;
Scanner scanner=new Scanner(System.in);
int x=scanner.nextInt();
while (x!=999){
s=new ListNode(x);
s.next=L;
L=s;
x=scanner.nextInt();
}
return L;
}
/**
* 尾插法建立链表
* @return 链表指针
*/
public ListNode createLsit2() {
ListNode L=null , s, r=null;
boolean isHead=true;
Scanner scanner = new Scanner(System.in);
int x = scanner.nextInt();
while (x != 999) {
s=new ListNode(x);
if(isHead){
L=r=s;
isHead=false;
}else {
r.next=s;
r=s;
}
x=scanner.nextInt();
}
r.next=null;
return L;
}
3.查找
/**
* 按位置查找:查找链表L中第i个结点
* @param L 链表
* @param i from 0
* @return 第i个结点,查找失败返回null
*/
ListNode getElem(ListNode L,int i){
ListNode p=L;
int j=0;
if(i<0) return null;
while (j<i){
if(p!=null){
p=p.next;
j++;
}else {//i>链表长度
return null;
}
}
return p;
}
/**
* 按值查找:查找值为e的结点的位置
* @param L 单链表
* @param e 给定值
* @return from 0,查找失败返回-1
*/
int getIndex(ListNode L,int e){
ListNode p=L;
int i=0;
while (p!=null&&p.data!=e){
p=p.next;
i++;
}
if(p==null)return -1;
else return i;
}
4.插入
//值为x的结点插到链表第i个位置
p=getElem(L,i-1);
s.next=p.next;
p.next=s;
5.删除
//将单链表的第i个结点删除
p=getElem(L,i-1);
q=p.next;
p.next=q.next;
free(q);
二、栈和队列
栈和队列的初始化和使用见二叉树先序遍历和层次遍历代码。
三、二叉树
1.二叉树节点的定义
public class BiTNode {
private int data;
private BiTNode leftChild;
private BiTNode rightChild;
public BiTNode(int data, BiTNode leftChild, BiTNode rightChild) {
this.data = data;
this.leftChild = leftChild;
this.rightChild = rightChild;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public BiTNode getLeftChild() {
return leftChild;
}
public void setLeftChild(BiTNode leftChild) {
this.leftChild = leftChild;
}
public BiTNode getRightChild() {
return rightChild;
}
public void setRightChild(BiTNode rightChild) {
this.rightChild = rightChild;
}
}
2.二叉树的定义
建造一棵如下二叉树:
public class BiTree {
/**
* 建立二叉树,返回二叉树根结点
* 说明:注意必须逆序建立二叉树,先建立子节点,再建立双亲结点,因为双亲结点会用到子节点
* @return 二叉树根结点
*/
public BiTNode init() {
BiTNode J = new BiTNode(8, null, null);
BiTNode H = new BiTNode(4, null, null);
BiTNode G = new BiTNode(2, null, null);
BiTNode F = new BiTNode(7, null, J);
BiTNode E = new BiTNode(5, H, null);
BiTNode D = new BiTNode(1, null, G);
BiTNode C = new BiTNode(9, F, null);
BiTNode B = new BiTNode(3, D, E);
BiTNode A = new BiTNode(6, B, C);
return A; //返回根节点
}
public void printNode(BiTNode node){
System.out.print(node.getData()+" ");
}
/**
* 递归先序遍历
* @param T 根结点
*/
public void preOrder(BiTNode T){
if(T!=null){
printNode(T);
preOrder(T.getLeftChild());
preOrder(T.getRightChild());
}
}
/**
* 递归中序遍历
* @param T 根结点
*/
public void inOrder(BiTNode T){
if(T!=null){
inOrder(T.getLeftChild());
printNode(T);
inOrder(T.getRightChild());
}
}
/**
* 递归后序遍历
* @param T 根结点
*/
public void postOrder(BiTNode T){
if(T!=null){
postOrder(T.getLeftChild());
postOrder(T.getRightChild());
printNode(T);
}
}
/**
* 非递归先序遍历,借助一个栈
* @param T 根结点
*/
public void preOrder2(BiTNode T){
Stack<BiTNode> stack = new Stack<BiTNode>();//初始化栈
BiTNode p=T;
while (p!=null||!stack.empty()){//stack.empty()栈判空
if(p!=null){
printNode(p);
stack.push(p);//入栈
p=p.getLeftChild();
}else {
p=stack.pop();//出栈;p=stack.peek()获取栈顶元素
p=p.getRightChild();
}
}
}
/**
* 非递归中序遍历,借助一个栈
* @param T 根结点
*/
public void inOrder2(BiTNode T){
Stack<BiTNode> stack = new Stack<BiTNode>();
BiTNode p=T;
while (p!=null||!stack.empty()){
if(p!=null){
stack.push(p);
p=p.getLeftChild();
}else {
p=stack.pop();
printNode(p);
p=p.getRightChild();
}
}
}
/**
* 非递归后序遍历,借助两个栈
* @param T 根结点
*/
public void postOrder2(BiTNode T){
Stack<BiTNode> stack = new Stack<BiTNode>();
Stack<BiTNode> output = new Stack<BiTNode>();//构造一个中间栈来存储逆后序遍历的结果
BiTNode p=T;
while (p!=null||!stack.empty()){
if(p!=null){
output.push(p);
stack.push(p);
p=p.getRightChild();
}else {
p=stack.pop();
p=p.getLeftChild();
}
}
while(output.size()>0){
printNode(output.pop());
}
}
/**
* 层次遍历二叉树,借助一个队列
* @param T 根结点
*/
public void levelOrder(BiTNode T){
Queue<BiTNode> queue = new LinkedList<BiTNode>();//初始化队列,LinkedList实现了Queue接口
BiTNode p;
queue.offer(T);//入队
while (!queue.isEmpty()){//队判空
p=queue.poll();//出队;p=queue.peek()获取队首元素
printNode(p);
if(p.getLeftChild()!=null){
queue.offer(p.getLeftChild());
}
if(p.getRightChild()!=null){
queue.offer(p.getRightChild());
}
}
}
/**
* 递归获取二叉树深度
* @param T 根结点
* @return 二叉树深度
*/
public int getDeepth(BiTNode T){
if(T!=null){
return Math.max(getDeepth(T.getLeftChild()),getDeepth(T.getRightChild()))+1;
}else {
return 0;
}
}
public static void main(String[] args) {
BiTree tree=new BiTree();
tree.levelOrder(tree.init());
}
}
四、图
图的存储以邻接表为例,下面为图顶点的定义:
public class GraphVertex {
private int data;//顶点值
private List<GraphVertex> neighborList =new ArrayList<>();//该顶点的相邻顶点表
public GraphVertex(int data) {
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public List<GraphVertex> getNeighborList() {
return neighborList;
}
public void addNeibor(GraphVertex v) {
neighborList.add(v);
}
}
图的遍历:
分别广度优先遍历和深度优先遍历如下无向图:
public class Graph {
private List<GraphVertex> vertexList=new ArrayList<>();//顶点表
private int vertexNum=0;//顶点数
private boolean visited[];//访问标记数组
private Queue<GraphVertex> queue=new LinkedList<GraphVertex>();//广度遍历辅助队列
/**
* 构造一张无向图,生成一个倒序的vertexList
* @return 返回图的一个顶点
*/
public GraphVertex init(){
GraphVertex v5=new GraphVertex(5);
vertexList.add(v5);
GraphVertex v4=new GraphVertex(4);
v4.addNeibor(v5);
vertexList.add(v4);
GraphVertex v3=new GraphVertex(3);
v3.addNeibor(v4);
v3.addNeibor(v5);
vertexList.add(v3);
GraphVertex v2=new GraphVertex(2);
v2.addNeibor(v3);
vertexList.add(v2);
GraphVertex v1=new GraphVertex(1);
v1.addNeibor(v2);
v1.addNeibor(v4);
vertexList.add(v1);
//补全相邻顶点
v2.addNeibor(v1);
v3.addNeibor(v2);
v4.addNeibor(v1);
v4.addNeibor(v3);
v5.addNeibor(v3);
v5.addNeibor(v4);
vertexNum=vertexList.size();
visited=new boolean[vertexNum];
return v1;
}
/**
* 打印某个顶点
* @param vertex 要打印的顶点
*/
public void printVertex(GraphVertex vertex){
System.out.print(vertex.getData()+" ");
}
/**
* 图的遍历
* @param mode mode==0,BFS;mode==1,DFS;
*/
public void traverse(int mode){
for(int i=0 ;i<vertexNum ;i++)
visited[i]=false;//初始化访问标记数组
for(int i=vertexNum-1;i>=0;i--){
if(!visited[i]){//遍历图中每个未访问过的顶点所在的连通分量
if(mode==0) BFS(vertexList.get(i));
else if(mode==1) DFS(vertexList.get(i));
}
}
}
/**
* 广度优先遍历一个连通分量,借助一个队列
* @param v 遍历起始顶点
*/
public void BFS(GraphVertex v){
printVertex(v);
visited[vertexList.indexOf(v)]=true;
queue.offer(v);
while(!queue.isEmpty()){
v=queue.poll();
for (int i=0;i<v.getNeighborList().size();i++){
//访问出队顶点的所有未访问过的相邻顶点
GraphVertex w=v.getNeighborList().get(i);
if(!visited[vertexList.indexOf(w)]){
printVertex(w);
visited[vertexList.indexOf(w)]=true;
queue.offer(w);
}
}
}
}
/**
* 深度优先遍历一个连通分量
* @param v 遍历起始顶点
*/
public void DFS(GraphVertex v){
printVertex(v);
visited[vertexList.indexOf(v)]=true;
for (int i=0;i<v.getNeighborList().size();i++){
GraphVertex w=v.getNeighborList().get(i);//v未访问过的相邻顶点
if(!visited[vertexList.indexOf(w)]){
DFS(w);
}
}
}
public static void main(String[] args) {
Graph graph=new Graph();
graph.init();
graph.traverse(0);
System.out.println();
graph.traverse(1);
}
}
1 2 4 3 5
1 2 3 4 5
说明:上例中,vertexList={5,4,3,2,1},对应访问标记数组下标0,1,2,3,4;
遍历是从顶点1开始的。
五、查找
public class Search {
/**
* 顺序查找
* @param a 查找表
* @param key 关键字
* @return 与key相等元素的下标
*/
public static int seq_search(int a[],int key){
int n=a.length;
int i;
for(i=n-1;i>=0&&a[i]!=key;i--);//从后往前;为了避免数组越界异常i>=0必须加上
return i;
}
/**
* 二分(折半)查找,只适用于有序的顺序表
* @param a 查找表
* @param key 关键字
* @return 与key相等元素的下标
*/
public static int bin_search(int a[],int key){
int low=0,high=a.length-1,mid;
while (low<=high){
mid=(low+high)/2;
if(key==a[mid]) return mid;
else if(key<a[mid]) high=mid-1;
else low=mid+1;
}
return -1;
}
public static void main(String[] args) {
int a[]={2,5,8,3,1,4};
int b[]={1,2,3,4,5,8};
for(int i=0;i<a.length;i++)System.out.print(a[i]+" ");
System.out.println();
Scanner scanner=new Scanner(System.in);
int key=scanner.nextInt();
System.out.println("顺序查找结果:"+seq_search(a,key));
for(int i=0;i<b.length;i++)System.out.print(b[i]+" ");
System.out.println();
key=scanner.nextInt();
System.out.println("二分查找结果:"+bin_search(b,key));
}
}
2 5 8 3 1 4
0
顺序查找结果:-1
1 2 3 4 5 8
0
二分查找结果:-1
六、内部排序
详见上一章《经典的8个内部排序算法》。
ps:以上java代码实现基于《王道-数据结构》伪代码。