# 算法--线性结构

#### 三、线性结构

##### 1、数组

//线性查找public static void queryByIndex(int[] arr){
    int target = 4;    int index = -1;    for(int i=0;i<arr.length;i++){        if(target == arr[i]){            index = i;            break;        }    }    System.out.println(index);}

/**
* 二分法查找,前提是数组的内容是有序的
* @param arr 数组
*/
public static void queryByMid(int[] arr){
int target = 4;
int index = -1;
int begin = 0;
int end = arr.length - 1;
int mid;
while(true){
mid = (begin+end)/2;
if(target == arr[mid]){
index = mid;
break;
}else if(target < arr[mid]){
end = mid - 1;
}else{
begin = mid + 1;
}
//不加这行会死循环
if(begin >= end){
break;
}
}

System.out.println(index);
}
##### 2、栈

class Stack{
int[] elements = new int[0];
/**
* 数组越界空指针异常不考虑
* @param element
*/
public void push(int element){
int[] arr = new int[elements.length + 1];
System.arraycopy(elements,0,arr,0,elements.length);
arr[arr.length -1] = element;
elements = arr;
}
/**
* 数组越界空指针异常不考虑
* @return
*/
public int pop(){
int[] arr = new int[elements.length - 1];
int len = elements.length;
int value = elements[len -1];
System.arraycopy(elements,0,arr,0,arr.length);
elements = arr;
return value;
}
public static void main(String[] args){
Stack stack = new Stack();
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
System.out.println(stack.pop());
System.out.println(stack.pop());
}
}
##### 3、队列

class Queue{
int[] elements = new int[0];
/**
* 数组越界空指针异常不考虑
* @param element
*/
public void push(int element){
int[] arr = new int[elements.length + 1];
System.arraycopy(elements,0,arr,0,elements.length);
arr[arr.length -1] = element;
elements = arr;
}
/**
* 数组越界空指针异常不考虑
* @return
*/
public int pop(){
int[] arr = new int[elements.length - 1];
int value = elements[0];
System.arraycopy(elements,1,arr,0,arr.length);
elements = arr;
return value;
}
public static void main(String[] args){
Queue queue = new Queue();
queue.push(2);
queue.push(3);
queue.push(4);
System.out.println(queue.pop());
System.out.println(queue.pop());
System.out.println(queue.elements.length);
}
}
##### 4、单向链表

class Node{
//节点数据
int data;
/**
* java对象在内存中是地址，可以理解下个节点的地址
*/
Node next;

public Node(int data){
this.data = data;
}

public Node append(Node node){
Node currentNode = this;
while(true){
Node nextNode = currentNode.next;
if(null == nextNode){
break;
}
currentNode = nextNode;
}
//当前节点是可变的，因为循环中重新赋值了
currentNode.next = node;
return this;
}

public Node next(){
return this.next;
}

public int getData(){
return this.data;
}
public boolean isLast(){
if(null == this.next){
return true;
}
return false;
}
/**
* 移除也只能移除当前节点的下个节点
*/
public void removeNext(){
Node deleteNode = this.next;
Node newNext = deleteNode.next();
this.next = newNext;
}

/**
* 只能插入当前节点后面
* @param node
*/
public void inset(Node node){
Node next = this.next;
this.next = node;
node.next = next;
}

public static void main(String[] args) {
Node node =new Node(1);
node.append(new Node(2)).append(new Node(3));
System.out.println(node.next().getData());

}
}
##### 5、单项循环链表

class Node{
//节点数据
int data;
//java对象在内存中是地址，可以理解下个节点的地址
Node next = this;

public Node(int data){
this.data = data;
}

public Node next(){
return this.next;
}

public int getData(){
return this.data;
}

/**
* 移除也只能移除当前节点的下个节点
*/
public void removeNext(){
Node deleteNode = this.next;
Node newNext = deleteNode.next();
this.next = newNext;
}

/**
* 只能插入当前节点后面
* @param node
*/
public void inset(Node node){
Node next = this.next;
this.next = node;
node.next = next;
}

public static void main(String[] args) {
Node node =new Node(1);
Node node2 =new Node(2);
Node node3 =new Node(3);
System.out.println(node.next().getData());
node.inset(node2);
node.inset(node3);
System.out.println(node.next().getData());
System.out.println(node3.next().getData());
}
}
##### 6、双向循环链表

class DoubleNode{

DoubleNode pre = this;

DoubleNode next = this;

int data;

public DoubleNode(int data){
this.data = data;
}

/**
* 往后增加节点
* @param node
*/
public void after(DoubleNode node){
//当前节点的下个节点
DoubleNode oldNext = this.next;
//新增的节点
this.next = node;

node.pre = this;
node.next = oldNext;

oldNext.pre = node;
}
}


##### 7、递归

/**
* 斐波那契数列 1 1 2 3 5 8 ...
*/
public static int test(int i) {
if (1 == i || 2 == i) {
return 1;
}
return test(i - 1) + test(i - 2);
}


汉诺塔
/**
* 汉诺塔
* 无论有多少盘子，都认为只有两个，上面的所有盘子和下面一个盘子。
*
* @param n    共n个盘子
* @param from 开始位置
* @param in   中间位置
* @param to   目标位置
*/
public static void test2(int n, char from, char in, char to) {
if (1 == n) {
System.out.println("第1个盘子从" + from + "移动到 " + to);
} else {
//移动上面的盘子到中间位置
test2(n - 1, from, to, in);
System.out.println("第" + n + "盘子从" + from + "移动到 " + to);
//把上面的所有盘子从中间位置移动到目标位置
test2(n - 1, in, from, to);
}
}


#### 八种常用排序算法

冒泡排序
 /**
* 就像水中的泡泡每次都是最大的先出水面
* @param arr
*/
public static void bubbleSort(int[] arr){
int swap = arr[0];
//控制比较多少轮
for(int i= 0;i < arr.length -1;i++){
//控制比较次数
for(int j=0;j < arr.length-i-1;j++){
if(arr[j] > arr[j + 1]){
swap = arr[j];
arr[j] = arr[j + 1];
arr[j+1] = swap;
}
}
}
}
快速排序 思想类似递归
public static void quickSort(int[] arr,int low,int high){
int i,j,temp,t;
if(low>high){
return;
}
i=low;
j=high;
//temp就是基准位
temp = arr[low];

while (i<j) {
//先看右边，依次往左递减
while (temp<=arr[j]&&i<j) {
j--;
}
//再看左边，依次往右递增
while (temp>=arr[i]&&i<j) {
i++;
}
//如果满足条件则交换
if (i<j) {
t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}

}
//最后将基准为与i和j相等位置的数字交换
arr[low] = arr[i];
arr[i] = temp;
//递归调用左半数组
quickSort(arr, low, j-1);
//递归调用右半数组
quickSort(arr, j+1, high);
}

public static void main(String[] args) {
int[] arr = new int[]{3,2,6,4,2,1};
Test.quickSort(arr,0,arr.length-1);
Arrays.stream(arr).forEach(item -> System.out.println(item));
}


//插入排序，下标前面的数据都是有序的
public static void insertSort(int[] arr){
//编列所有数字
for(int i=1;i<arr.length;i++){
//如果当前数字比前一个数字小
if(arr[i]<arr[i-1]){
int temp = arr[i];
int j;
//遍历当前数字前面的所有数字
for(j = i-1;j>=0 && temp<arr[j];j--){
//把前一个数字赋值给后一个数字
arr[j+1] = arr[j];
}
把临时变量（外层for循环的当前元素）赋给不满足条件的后一个元素
arr[j+1] = temp;
}
}
}
//希尔排序 最要概念是步长
public static void shellSort(int[] arr){
int k=1;
//编列所有的步长
for(int d = arr.length/2;d > 0;d/=2){
//遍历所有元素
for(int i=d;i<arr.length;i++){
//编列本组中所有元素
for(int j = i-d;j>=0;j-=d){
if(arr[j]>arr[j+d]){
int temp = arr[j];
arr[j] = arr[j+d];
arr[j+d] = temp;
}
}
}
System.out.println(k+Arrays.toString(arr));
k++;
}
}


//选择排序 每次循环记录最小下标
public static void selectSort(int[] arr){

//控制比较多少轮
for(int i= 0;i < arr.length -1;i++){
int minIndex=i;
//把当前遍历的数和后面所有的数依次比较，并记录最小的下标
for(int j = i+1;j < arr.length-i;j++){
if(arr[minIndex] > arr[j]){
//记录下最小的下标数
minIndex = j;
}
}
//交换位置
if(i!=minIndex){
int temp = arr[i];
arr[i]=arr[minIndex];
arr[minIndex]=arr[i];
}
}
}

//归并排序
public static void merge(int[] arr,int low,int middle,int hight){
//用于存储归并后的临时数组
int[] temp = new int[hight-low+1];
//记录第一个数组中需要遍历的下标
int i = low;
//记录第二个数组中需要遍历的下标
int j = middle+1;
//用于记录在临时数组中存放的下标
int index = 0;
//遍历两个数组取出小的数字，放入临时数组
while(i<=middle&&j<=hight){
//第一个数组的数据更小
if(arr[i]<=arr[j]){
//把小的数据放入临时数组中
temp[index] = arr[i];
//让下标向后移动一位
i++;
}else{
temp[index] = arr[j];
j++;
}
index++;
}
//处理多余的数据
while(j<=hight){
temp[index] = arr[i];
j++;
index++;
}
while(i<-middle){
temp[index]=arr[i];
i++;
index++;
}
//把临时数组中的数组重新存入原数组
for(int k=0;k<temp.length;k++){
arr[k+low] = temp[k];
}
}


//基数排序，可支持队列

int max = Integer.MIN_VALUE;
for(int i=0;i<arr.length;i++){
if(arr[i]>max){
max = arr[i];
}
}

int maxLength = (max+"").length();
//用于临时存储数据的二维数组
int[][]  temp = new int[10][arr.length];
int[] count = new int[10];
for(int i=0;i<maxLength;i++,n*=10){
for(in j=0;j<arr.length;j++){
//计算余数
int ys = arr[j]/n%10;
temp[ys][count[ys]] = arr[j];
//记录数量
count[ys]++;
}
//记录取的元素需要放的位置
int index=0;
//把数字取出
for(int k=0;k<count.length;k++){
if(count[k]!=0){
for(int l=0;l<count[k];l++){
arr[index++] = temp[k][l];
}
}
count[k] = 0;
}
}

}


posted @ 2020-03-18 10:51  码农的进击  阅读(418)  评论(0编辑  收藏  举报