一、经典问题算法
1,肥婆那切数列
普通方法
public class Fibonaccil(){
//定义三个变量和方法
int a=1,b=1,c=0;
System.out.print(a+" "+b+" ");
for(int i=1;i<=18;i++){
c = a + b;
a = b;
b = c;
System.out.print(c+" ");
}
}
数组方法
public class Fibonacci2(){
//定义数组
int a[20],a[0]=1;a[1]=1;
for(int i=2;i<aa.length;i++){
a[i]=a[i-1]+a[i-2];
}
for(int i=0;i<aa.length;i++){
System.out.print(a[i]);
}
}
递归方法
public class Fibonacci3(){
//定义变量
private static int getFibo(int i){
if(i ==1||i == 2)
return 1;
else
return getFibo(i-1)+getFibo(i-2);
}
public static void main(String[] args){
for(int j=1; j<=20;j++){
System.out.print(getFibo(j)+" ");
}
}
}
2,约瑟夫环
n:人的总数
start:开始报数的序号,start<n
m:出列的标记
public static void main(String[] args){
//50人,从第一个人开始数,数到3的人出列
countThree(50,0,3);
}
private static void countThree(int n, int start, int m){
List<Integer> list = new ArrayList<Integer>();
//初始化列表
for (int i = 1; i <= n; i++){
list.add(i);
}
while(list.size()>0){
//将前两个一如列表尾端
for(int j=0; j<m-1; j++){
list.add(list.remove(start));
}
//打印出列的序号
System.out.println(list.remove(start));
}
}
二、数据结构
查找
int[] intArr = new int[10];
intArr[0] = 1;
intArr[1] = 2;
intArr[2] = 3;
intArr[3] = 4;
intArr[4] = 5;
intArr[5] = 6;
int[] intArr = {1,2,3,4,5,6};
public class MyArray{
private long[] arr;
private int size=0;
public MyArray(){
arr = new long[10];
}
public MyArray(int maxSize){
arr = new long[maxSize];
}
//向数组中插入数据
public void insert(long element){
arr[size] = element;
size++;
}
//显示数组中数据
public void show(){
for(int i=0; i<size; i++){
if(i==0){
System.out.print(arr[i])
}
}
}
//根据value进行查询
public int queryByValue(long element){
int i;
for(i=0; i<size; i++){
if(arr[i] == element) break;
}
if(i == size){
return -1;
}else{
return -1;
}
}
//根据索引查找值
public long queryByIndex(int index){
if(index >= size || index<0){
throw new ArrayIndexOutOfBoundsException();
}else{
return arr[index];
}
}
//删除元素
public void delete(int index){
if(index >= size || index<0){
throw new ArrayIndexOutOfBoundsException();
}else{
//当size=maxSize,删除最后一个数时,不会执行for
for(int i = index; i<size-1;i++){
arr[index] = arr[index +1];
System.out.println("for");
}
}
size--;
}
//更新数据
public void update(int index, long value){
if(index >= size || index<0){
throw new ArrayIndexOutOfBoundException();
}else{
arr[index] = value;
}
}
}
二分查找法:(前提是:有序)
public int binarySearch(long value){
public middle = 0;
int left = 0;
int right = size - 1;
while(true){
middle = (left + right)/2;
if(arr[middle] == value){
return middle;//①value为中间值,比较次数为1
}else if(left>right){
return -1;
}else{
if(arr[middle]<value)//value偏大
left = middle+1;
}else{//value偏小
right = middle-1;
}
}
}
}
public class binarySearch(long value){
long middle = 0;
left = arr[0];
right = arr[size-1];
while(true){
middle = (left+right)/2;//重写时把这个忘了
if(arr[middle]==value)
return arr[middle];
else if(value>arr[middle]){
left = middle+1;
}else{
right = middle-1;
}
}
}
排序
冒泡排序
//bubble sort;
public static void bubbleSort(long[] arr){
long temp;
for(int i=0; i<arr.length;i++){//外部的i向前循环,正序
for(int j=arr.length-1;j>i;j--){
if(arr[j]<arr[j-1]){//内部的j向后循环,逆序
temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
}
}
}
}
public static void bubbleSort(long[] arr){
long temp;
for(int i=0; i<arr.length;i++){
for(int j=arr.length-1; j>i;j--){
if(a[j]>a[j--]){//第一次重写时把交换条件弄丢了。
temp = a[i];//交换的数组小标也写错了。应该是j
a[i] = a[i--];
a[i--] = temp;
}
}
}
}
选择排序
基本思想:在排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中
再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。
与冒泡排序相比,选择排序将必要的交换次数从O(N*N)减少到O(N),但比较次数还是保持才O(N)
select sort
public static void selectSort(long[] arr){
long temp;
for(int i=0; i<arr.length-1;i++){//外层排序,是正序。
int k=i;//k用来记录最小数的数组下标
for(int j=i+1;j<arr.length; j++){//内层排序也是正序,起始点为每次i的下一个元素。
if(arr[j]<arr[k]){
k=j;
}
}
temp = arr[i];
arr[i] = arr[k];
arr[k] = temp;
}//外层循环中实现交换
}
插入排序
基本思想:在要排序的一组数组中,假设前面(n-1)[n>=2]个数已经是拍好顺序的(局部有序),现在
要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
在插入排序中,一组数据仅仅是局部有序的;而冒泡排序和选择排序,一组数据项在某个时刻是完全有序的。
insert sort
public static void insertSort(long[] arr){
long temp;
for(int i=1; i<arr.length;i++){//外层循环,用i来表示遍历整个序列
temp = arr[i];//记录要插入的元素
int j = i;
while(j>=1 && arr[j-1]>temp){//找到待插入元素应该插入的位置,从小到大,如果发现比待插入元素大的元素,和带插入元素进行交换。
arr[j] = arr[j-1];
j--;
}
arr[j] = temp;//在应插入位置插入记录元素。
}
}
存储结构
栈的数组实现
public class Mystack{
private long[] arr;
private int top;
public MyStack(){
arr = new long[10];
top = -1;
}
public MyStack(int maxSize){
arr = new long[maxSize];
top = -1;
}
//进栈
public void push(long value){
arr[++top] = value;
}
//出栈
public long pop(){
return arr[top--];
}
//读栈顶
publid long peek(){
return arr[top];
}
//判空
public boolean isEmpty(){
return (top == -1);
}
//判栈满
public boolean isFull(){
return (top == arr.length-1);
}
}
队列
队列的数组实现
public class MyQueue{
private long[] arr;
private int size;
private int front;
private int rear;
public MyQueue(){
arr = new long[10];
size = 0;
front = 0;
rear = -1;
}
public MyQueue(int maxSize){
arr = new long[maxSize];
size = 0;
front = 0;
rear = -1;
}
//队尾插入元素
public void insert(long value){
if(isEmpty()){
throw new ArrayIndexOutOfBoundsException();
}
if(rear == arr.length-1){//队列环绕式处理,把插入元素的队尾 重置为-1
rear = -1;
}
arr[++rear] = value;//插入元素
size++;
}
//队首删除元素
public long remove(){
long value = arr[front++];
if(front == arr.length){
front = 0;
}
size--;
return value;
}
//取队首
public long peek(){
return arr[front];
}
//判空
public boolean isEmpty(){
return(size == 0);
}
//判满
public boolean isFull(){
return (size == arr.length);
}
}
链表
链表的定义
pubic class Link{
public long data;
public Link next;
public Link(long data){
this.data = data;
}
public void displayLink(){
System.out.print(data+"--->");
}
}
单链表
public class LinkList{
private Link first;
public LinkList(){
this.first = null;
}
//表头插入
public void insertFirst(long value){
Link newLink = new Link(value);
newLink.next = first;
first = newLink;
}
//表头删除并返回
public Link deleteFirst(){
if(first == null){
return null;
}
Link temp = first;
first = first.next;
return temp;
}
//输出遍历链表
public void displayList() {
Link current = first;
while(current != null){
current.displayLink();
current = current.next;
}
System.out.println();
}
//查找指定节点
public Link find(long key){
Link current = first;
while(current.data != key){
if(current.next == null){
return null;
}else{
current = current.next;
}
}
return current;
//while(current.next != null)
//{
// if(current.data == key){
// return current;
// }else{
// current = current.next;
// }
// return null;
//}
}
//删除指定节点
public Link delete(long key){
Link current = first;
Link previous = first;
while(current.data != key){
if(current.next == null){
return null;
}else{
previous = current;
current = current.next;
}
}//找到并跳出循环
if(current == first){
first = first.next;
}else{
previous.next = curren.next;//删除
}
return current;
}
}
双端链表
链表中保存着对最后一个链结点的引用
public class FirstLastList{
private Link first;
private Link last;
public FirstLastList(){
this.first = null;
this.last = null;
}
public boolean isEmpty(){
return first == null;
}
//表头添加节点
public void insertFirst(long value){
Link newLink = new Link(value);
if(isEmpty()){
last = newLink;
}
newLink.next = first;
first = newLink;
}
//表尾添加节点
public void insetLast(long value){
Link newLink = new Link(value);
if(isEmpty){
first = newLink;
}else{
last.next = newLink;
}
last = newLink;
}
//删除表头
public Link deleteFirst(){
Link temp = first;
}
}
双向链表
public class DoubleLink{
public long data;
public DoubleLink next;
public DoubleLink previous;
public DoubleLink(long data){
this.data = data;
}
public void displayLink(){
System.out.print(data+"<==>");
}
}
public class DoublyLinkedList{
private DoubleLink first;
private DoubleLink last;
public DoubleLinkedList(){
this.first = null;
this.last = null;
}
public boolean is Empty(){
return first == null;
}
//头部插入
public void insertFirst(long value){
DoubleLink newLink = new DoubleLink(value);
if(isEmpty()){
last = newLink;
}else{
first.previous = newLink;
newLink.next = first;
}
first = newLink;
}
//尾插法
public void inserLast(long value){
DoubleLink newLink = new DoubleLink(value);
if(isEmpty()){
first = newLink;
}else{
last.next = newLink;
newLink.previous = last;
}
last = newLink;
}
//头删除
pubic DoubleLink deleteFirst(){
DoubleLink temp = first;
if(first.next == null){
last = null;
}else{
first.next.previous = null;
}
first = first.next;
return temp;
}
//尾删除
public DoubleLink deleteLast(){
DoubleLink temp = last;
if(first.next == null){
first = null;
}else{
last.previous.next = null;
}
last = last.previous;
return temp;
}
//指定节点后插入
public boolean insertAfter(long key, long data){
DoubleLink current = first;
while(current.data != key){
if(current.next == null){
return fasle;
}else{
current = current.next;
}
}//循环遍历,找到跳出并返回current指针,否则返回false;
DoubleLink newLink = new DoubleLink(data);
if(current == last){//如果是指定节点是尾节点
newLink.next = null;
last = newLink;
}else{
newLink.next = current.next;
current.next.previous = newLink;
}
current.next = nweLink;
newLink.previous = current;
return true;
}
//删除指定节点
public DoubleLink deleteKey(long key){
DoubleLink current = first;
while(current.data != key){//①找到指定节点,没有放回null;
if(current.next == null){
return null;
}else{
current = current.next;
}
}//跳出循环并找到指定current.data
if(current == first){//②根据current的前驱结点来完成current前一结点到后一节点的连接。如果没有前驱节点比如首节点的情况,直接删除首节点的操作,first = first.next;
first = first.next;
}else{
current.previous.next = current.next;
}
if(current == last){//③根据curren的后继结点来完成current后一节点都前一结点的指向,如果没有后继结点,比如刚好是尾节点,直接删除尾节点,last=last.previous
last = last.previous;
}else{
current.next.previous = current.previous;
}
return current;
}
//正序输出
public void displayForward(){
System.out.print("first-->last:");
DoubleLink current = first;
while(curren != null){
current.displayLink();
current = current.next;
}
System.out.println();
}
//逆序输出
public void displayBackword(){
System.out.print("last-->first:");
DoubleLink current = last;
while(current != null){
current.displayLink();
current = current.previous;
}
System.out.println();
}
}
递归
递归调用:一种在方法中定义中调用方法自身的编程技术。解决递归问题的直接转化法和间接转化法。
三角数:第n项为n-1项与n的和
public static int triangleByRecursion(int n){
if(n == 1){
return 1;
}else{
return n + triangleByRecursion(n-1);
}
}
Fibonacci数列
public static int fibo(int n){
if(n==1 || n==2){
return 1;
}else{
return fibo(n-1) + fibo(n-2);
}
}
汉诺塔问题
public static doTowers(int topN, char from, char inter, char to){
if(topN == 1){
System.out.println("Disk 1 from" + from +"to" +to);
}else{
doTowers(topN-1,from,to,inter);
System.out.println("Disk" + topN +"from" +from +"to" +to);
doTowers(topN-1,inter,from,to);
}
}
尾递归:直接转换法,尾递归是指在递归算法中,递归调用语句只有一个,而且是处在算法的最后
阶乘
public long fact(int n)
{
if (n==0) return 1;
else return n*fact(n-1);//递归的调用在算法最后的结束处,不需要保存中间值。
}
public long fact(int n)
{
int s=0;
for (int i=1; i
s=s*i; //用s保存中间结果
return s;
}
单向递归:调用语句在递归算法的最后,尾递归是单项递归的特例。递归调用的参数之间没有关系。
单项递归可以设置一些中间变量,保存中间值。
public int f(int n)
{
if (n= =1 | | n= =0) return 1;
else return f(n-1)+f(n-2);
}
public int f(int n)
{
int i, s;
int s1=1, s2=1;
for (i=3; i {
s=s1+s2;
s2=s1; // 保存f(n-2)的值//利用中间变量保存值
s1=s; //保存f(n-1)的值
}
return s;
}
间接转化法解决递归问题:
使用栈保存中间结果,一般需要根据递归函数在执行过程中栈的变化得到。其一般过程如下:
将初始化状态s0进栈
while(栈不为空){
退栈,将栈顶元素赋给s;
if (s是要找的结果) 返回;
else {
寻找到s的相关状态s1;
将s1进栈
}
}
树
有序数组插入数据项和删除数据项太慢,链表查找数据太慢,在树中能快速地查找,插入和删除数据项。
树:从根到任何一个节点有且只有一条路径。
二叉树
1.被删除节点没有子树的情况,直接删除,并修改对应父节点的指针为空。
2.对于只有一个子树的情况,考虑将其子树作为其父节点的子树,关于是左还是右,根据被删除的节点确定。
3.最复杂的是有两个子数的情况,可以考虑两种方法,都是同样的思想:用被删除节点A的左子树的最右节点或者A的右子树的最左节点作为替代A的节点,并修改相应的最左或最右节点的父节点的指针,修改方法类似2 ,不做细致讨论
public class Node{
long data;
Node leftChild;
Node rightchild;
public Node(long data){
this.data = data;
}
}
public void insert(long value){
Node newNode = new Node(value);
if(root == null){//如果是空树
root = newNode;
}else{
Node current = root;
Node parent;
while(true){
parent = current;//parent指向当前节点
if(value < current.data){//待插入节点值小于根
current = current.leftChild;//分配到左子树中
if(current == null){//判断是否到应该插入的位置,也就是到达了叶子节点
parent.leftChild = newNode;//插入节点
return;
}else{
current = current.rightchild;
if(current == null){
parent.rightChild = newNode;
return;
}
}
}
}
}
}
public void insert(long value){
Node newNode = new Node(value);
if(root == null){//①判空
root = newNode;
}else{
Node current = root;
Node parent;
while(true){//②循环子树
//第一次写时,忘记了循环,这个是以树为子问题的解决方法
parent = current;
if(data<current.data){//③判左右
current = curren.leftChild;
if(current == null){//④判是否为子节点
parent.leftChild = newNode;
return;//第一次书写忘了return。
}
}else{
current = curren.rightChild;
if(current == null){
parent.rightChild = newNode;
return;
}
}
}
}
}
public Node find(long value){
Node current = root;
while(current.data != value){
if(value < current.data){
current = current.leftChild;
}else{
current = current.rightChild;
}
if(current == null){
return null;
}
}
return current;
}
//树节点的删除
//首先找到指定要删除的节点,有三种情况要考虑:①节点为叶子节点,没有子节点。
②节点只有一个子节点,③节点有两个节点
public boolean delete(long value){
Node current = root;
Node parent = current;
boolean isLeftChild = true;
while(current.data != value){
parent = current;
if(value < curren.data){
current = curren.leftChild;
isLeftChild = true;
}else{
current = current.rightChild;
isLeftChild = false;
}
if(current == null){
return false;
}
}find it
//find no child
if(current.leftChild = null && current.rightChild == null){
if(current == root){
root = null;
}else if(isLeftChild){
parent.leftChild = null;
}else{
parent.rightChild = null;
}
}else if(current.leftChild == null){
// if no left child, replace with right subtree
if(current == root){
root = current.rightChild;
}else if(isLeftChild){
parent.leftChild = current.rightChild;
}else{
parent.rightChild = current.rightChild;
}
}else if(current.right == null){
if(current == root){
root = current.leftChild;
}else if(isLeftChild){
parent.leftChild = current.leftChild;
}else{
parent.rightChild = current.leftChild;
}
}else{
//two childdren
Node successor = getSuccessor(current);
if(current == root){
root = successor;
}else if(isLeftChild){
parent.leftChild = successor;
}else{
parent.rightChild = successor;
}
successor.leftChild = current.leftChild;
}
return true;
}
private Node getSuccessor(Node delNode) {
Node current = delNode.righttChild; //go to right child
Node successorParent = delNode;
Node successor = delNode;
while(current != null) { //until no more
successorParent = successor;
successor = current;
current = current.leftChild; //go to left child
}
// if successor not right child, make connections
if(successor != delNode.righttChild) {
successorParent.leftChild = successor.righttChild;
successor.righttChild = delNode.righttChild;
}
return successor;
}
//二叉树的删除功能
public boolean delete(long value){
Node current = root;
Node parent = current;
boolean isLeftChild = true;
//1.查找指定节点的,并用current指向该节点。
while(current.data != value){
parent = current;
if(value < current.data){
current = current.leftChild;
isLeftChild = true;
}else{//
current = current.rightChild;
isLeftChild = false;
}
if(current == null){
return false;
}
}
//2.对查找出的节点进行三种不同情况的进行判断和相应操作
if(current.leftChild == null && current.rightChild == null){//①子节点
if(current == root){
root = null;
}else if(isLeftChile){
parent.leftChild = null;
}else{
parent.rightChild = null;
}
}else if(current.leftChild == null){//②current只有右节点,对parent的左右两个节点进行判断操作
if(current == root){
root = current.leftChild;
}else if(isLeftChild){
parent.leftChild = current.rightChild;//parent 为current父节点,如果current没有左子树就把current的右字树直接接到父节点的左子树中。实现没有左子树的current节点的左子树的删除。
}else{
parent.righttChild = current.righttChild;
}
}else if(current.rightChild == null){//③current只有左节点,对parent的左右两边进行删除,把相应current的左节点挂靠到parent的左右节点上。
if(current == root){
root = current.leftChild;
}else if(isLeftChild){
parent.leftChild = current.leftChild;
}else{
parent.rightChild = current.leftChild;
}
}else{ //④current具有两个节点,
//获得current下的所有字树
private Node getSuccessor(Node delNode){
Node current = delNode.rightChild;
Node successorParent = delNode;
Node successor = delNode;
while(current != null){
successorParent = successor;
successor = current;
current = current.leftChild;
}
if(successor != delNode.right){
successorParent.leftChild = successor.rightChild;
}
}
Node successor = getSuccessor(current);
//把获得的剩余的字树挂靠到父节点parent上面
if(current == root){
root = successor;
}else if(isLeftChild){
parent.leftChild = successor;
}else{
parent.rightChild = successor;
}
successor.leftChild = current.leftChild;
}
return true;
}
//二叉树的遍历
先根遍历,先序遍历
public void frontOrder(Node node){
if(node != null){
System.out.println(node.data);
frontOrder(node.leftChild);
frontOrder(node.rightChild);
}
}
中根遍历,中序遍历
public void inOrder(Node node){
if(node != null){
inOrder(node.leftChild);
System.out.println(node.data);
inOrder(node.rightChild);
}
}
后根遍历,后序遍历
public void inOrder(Node node){
if(node != null){
inOrder(node.leftChild);
inOrder(node.rightChild);
System.out.println(node.data);
}
}
红黑树与平衡树:
图
1)图是一种和树相像的数据结构,通常有一个固定的形状,这是由物理或抽象的问题来决定的。
2)如果两个顶点被同一条边连接,就成这两个顶点邻接
3)路径是从一个点到另一个点经过的序列
4)至少有一条路径可以连接所有的顶点,那么这个图就是联通的,否则是非联通
5)有向图和无向图
6)带权图
//Vertex顶点类
public class Vertex{
char label;
boolean wasVisited;
public Vertex(char label){
this.label = label;
wasVisited = false;
}
}
//Graph图类
public class Graph{
private int maxSize = 20;
private Vertex[] vertexList;//节点列表,存储节点
private int[][] adjmat;//邻接矩阵,存储边
private int nVertex;//记录节点数目
private MyStack theStack;//
public Graph(){
vertexList = new Vertex[maxSize];
adjmat = new int[maxSize][maxSize];
nVertex = 0;
theStack = new MyStack();
for(int i=0; i<maxSize; i++){
for(int j=0; j<maxSize; j++){
adjmat[i][j] = 0;
}
}
}
public void addVertex(char label){
vertexList[nVertex++] = new Vertex(label);
}
public void addEdge(int start,int end){
adjmat[start][end] = 1;
adjmat[end][start] = 1;
}
public void display(){
for(int i=0; i<nVertex; i++){
System.out.println(vertexList[i].label);
}
}
}
图的搜索
1)图的搜索是指从一个指定的顶点到达那些顶点
2)有两种常用的方法用来搜索图:深度优先搜索(DFS)和广度优先搜索(BFS)
深度优先搜索通过栈来实现,而广度优先搜索通过队列来实现。
3)深度优先搜索
①如果可能,访问一个邻接的未访问的顶点,标记它,并把它放入栈中。
②当不能执行规则1时,如果栈不为空,就从栈中弹出一个顶点。
③当不能执行规则1和规则2时,就完成了整个搜索过程。
DFS
public void dfs(){
vertexList[0].wasVisited = true;
System.out.println(vertexList[0].label);
theStack.push(0);
while(!theStack.isEmpty()){
int v = getAdjUnvisitedVertex((int) theStack.peek);
if(v == -1){
theStack.pop();
}else{
vertexList[V].wasVisited = true;
System.out.println(vertexList[V].label);
theStack.push(V);
}
}
for(int i=0; i<nVertex; i++){
vertexList[i].wasVisited = false;
}
}
public int gerAdjUnvisitedVertex(int V){
for(int i=0; i<nVertex; i++){
if(adjmat[V][i]==1 && vertexList[i].wasvisited == false){
return i;
}
}
return -1;
}
4)广度优先搜索
①访问下一个邻接的未访问过的,这个顶点必须是当前节点的邻接点。标记它,并把它插如到队列中。
②如果无法执行规则1,那么就从对猎头取出一个顶点,并使其作为当前顶点。
③当队列为空不能执行规则2时,就完成了整个搜索。
BFS
5)图的最小生成树
连接每个顶点最少的连线,最小生成树边的数量总是比定点的数量少1
public void mast(){
vertexList[0].wasVisited = true;
theStack.push(0);
while(!theStack.isEmpty()){
int currentVertex = (int) theStack.peek();
int v = getAdjUnvisitedVertex(currentVertex);
if( v == -1){
theSatck.pop();
}else{
vertexList[v].wasVisited = true;
System.out.print(vertexList[currentVertex].label+"-");
System.out.println(vertexList[v].label);
theStack.push(v);
}
}
for(int i=0; i<nVertex; i++){
vertexList[i].wasVisited = false;
}
}