一、线型数据结构
00.复杂度
(1)时间复杂度
每访问一个元素,时间复杂度记为1。如果一个数组长度为n,如果我们用遍历的方式来进行操作,那么访问n次才能够确定,时间复杂度记为n;
常见的时间复杂度有:1,N,Log n,N2,N3
(2)空间复杂度
原始数据空间为n,我们新开辟的空间大小是n的多少倍。
01.数组
**特点:**数组对象直接指向数组首地址,物理空间上是连续的。数据呈线状排列。
**优点:**在查找的时候,效率高。
**缺点:**因为空间是连续的,所以当磁盘的控件碎片较多的时候,我们可能无法存入大数据。即使内存空间足够,也无法存储。
(1)遍历与求和
public class Array001 {
//数组遍历
public static void print(int[] arr) {
if (arr == null || arr.length == 0) {
System.out.println("数组为空,取消遍历");
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
//数组求和
public static int sum(int[] arr) {
int total = 0;
if (arr == null) {
return total;
}
for (int i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
public static void main(String[] args) {
int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
System.out.println("数组遍历为:");
print(arr);
System.out.println();
System.out.println("数组的和为:" + sum(arr));
}
}
(2)数组排序
a.冒泡排序
特点是一遍比较,一边交换;
/**
* 冒泡排序
*/
public class BubbleSort {
public static void sort(int[] arr) {
if (arr == null || arr.length == 0 || arr.length == 1) {
return;
}
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
public static void main(String[] args) {
int[] arr = new int[]{4, 3, 5, 7, 9, 8, 6, 1, 2};
sort(arr);
for (int i : arr) {
System.out.println(i);
}
}
}
b.选择排序
特点是先遍历选择最大值的索引,再和未排序的最后一个元素进行交换;
/**
* 选择排序
*/
public class SelectionSort {
public static void sort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
int maxIndex = 0;
for (int j = 1; j < arr.length - i; j++) {
if (arr[j] > arr[maxIndex]) {
maxIndex = j;
}
}
int temp = arr[maxIndex];
arr[maxIndex] = arr[arr.length - i - 1];
arr[arr.length - i - 1] = temp;
}
}
public static void main(String[] args) {
int[] arr = new int[]{3, 2, 5, 6, 9, 1, 4, 7, 9, 8};
sort(arr);
for (int i : arr) {
System.out.println(i);
}
}
}
(3)有序数组的合并
思路:新建一个足够长度的新数组,循环比较两个数组的较小值,谁小,谁就放到新数组中。
/**
* 合并两个有序的数据
*/
public class OrderlyArrayMerge {
public static int[] merge1(int[] arrA, int[] arrB) {
if (arrA == null) {
return arrB;
}
if (arrB == null) {
return arrA;
}
int[] result = new int[arrA.length + arrB.length];
int p1 = 0; //第一个数组的索引
int p2 = 0; //第二个数组的索引
int pr = 0; //新数组的索引
while (p1 < arrA.length && p2 < arrB.length) { //当p1和p2都没有越界时
if (arrA[p1] < arrB[p2]) { //谁小,谁就放在新数组里
result[pr++] = arrA[p1++];
} else {
result[pr++] = arrB[p2++];
}
}
if (p1 >= arrA.length) { //如果p1放完了
while (p2 < arrB.length) { //则把p2剩余的放到新数组里
result[pr++] = arrB[p2++];
}
} else {
while (p1 < arrA.length) {
result[pr++] = arrA[p1++];
}
}
return result;
}
public static int[] merge2(int[] arrA, int[] arrB) {
if (arrA == null) {
return arrB;
}
if (arrB == null) {
return arrA;
}
int[] result = new int[arrA.length + arrB.length];
int p1 = 0;
int p2 = 0;
int pr = 0;
while (p1 < arrA.length || p2 < arrB.length) { //当p1和p2有一个没放完时即循环
//如果p2越界或p1比p2小,用p1的数据
if (p2 >= arrB.length || arrA[p1] < arrB[p2]) {
result[pr++] = arrA[p1++];
} else {
result[pr++] = arrB[p2++];
}
}
return result;
}
public static void main(String[] args) {
int[] a = new int[]{1, 3, 5, 7, 9, 11, 13, 15};
int[] b = new int[]{2, 4, 5, 6, 8, 9, 10};
// int[] c = merge1(a, b);
int[] c = merge2(a, b);
for (int i : c) {
System.out.println(i);
}
}
}
02.链表
**特点:**空间可以不是连续的。需要在存放数据的同时,多创建一个空间用来存放数据。
**优点:**不受空间大小的影响,只要有空间,就能存储数据,不会受空间连续的制约。
**缺点:**查找效率没有数组高;需要多开辟一块空间。
(1)遍历与求和
-
链表结点类Node
public class Node { public int val; public Node next; public Node() { } public Node(int val) { this.val = val; } }
-
代码演示
public class LinkTable001 {
//遍历链表
public static void print(Node node) {
while (node != null) {
System.out.print(node.val + " ");
node = node.next;
}
}
//递归遍历
public static void print2(Node node) {
//递归出口
if (node == null) return;
//递归操作
System.out.print(node.val + " ");
//下一次递归
print2(node.next);
//每次完成之后做的事情
System.out.print(node.val + " ");
}
//链表求和
public static int sum(Node node) {
if (null == node) {
return 0;
}
int total = 0;
while (node != null) {
total += node.val;
node = node.next;
}
return total;
}
//链表递归求和
public static int sum2(Node node,int total) {
//递归出口
if (node == null) return total;
//递归操作
total += node.val;
//下一次递归
return sum2(node.next, total);
}
public static void main(String[] args) {
Node head = new Node(1);
Node node1 = new Node(2);
Node node2 = new Node(3);
Node node3 = new Node(4);
Node node4 = new Node(5);
head.next = node1;
node1.next = node2;
node2.next = node3;
node3.next = node4;
System.out.println("链表普通遍历:");
print(head);
System.out.println();
System.out.println("链表递归遍历:");
print2(head);
System.out.println();
System.out.println("链表求和:" + sum(head));
System.out.println("链表递归求和:" + sum2(head, 0));
}
}
(2)链表逆置
public class LinkTable002 {
//链表逆置
public static Node change(Node node) { //a传进来
if (node.next.next != null) {
Node result = change(node.next); //a,change b;
node.next.next = node;
node.next = null;
return result;
} else { //如果是倒数第二个结点
Node result = node.next; //记录最后一个结点
node.next.next = node; //最后一个结点指向前一个结点
node.next = null; //前一个结点指向空
return result; //返回最后一个结点
}
}
public static Node change2(Node node) {
Node result = null;
if (node.next.next != null) {
result = change(node.next);
} else {
result = node.next;
}
//递归操作
node.next.next = node;
node.next = null;
return result;
}
public static void main(String[] args) {
Node a = new Node(1);
Node b = new Node(2);
Node c = new Node(3);
Node d = new Node(4);
Node e = new Node(5);
a.next = b;
b.next = c;
c.next = d;
d.next = e;
}
}
03.栈
-
自定义栈MyStack
/** * 用数组封装栈 */ public class MyStack { private int top; private int[] data; public MyStack(int size) throws Exception { if (size <= 0) { throw new Exception("栈的长度必须大于0"); } this.data = new int[size]; } public void push(int value) throws Exception { if (top >= this.data.length) { throw new Exception("栈满了"); } data[top++] = value; } public int pop() throws Exception { if (top <= 0) { throw new Exception("栈空了"); } return data[--top]; } }
-
测试栈
public class StackTest { public static void main(String[] args) throws Exception { MyStack myStack = new MyStack(3); myStack.push(1); myStack.push(2); myStack.push(3); System.out.println(myStack.pop()); System.out.println(myStack.pop()); System.out.println(myStack.pop()); } }
04.队列
(1)用链表实现队列
/**
* 用链表实现队列
*/
public class MyQueue {
private Node head; //队列的头
private Node tail; //队列的尾
private int maxSize; //队列的最大容量
private int size; //队列的当前存值个数
public MyQueue(int maxSize) {
this.maxSize = maxSize;
this.size = 0;
}
public void push(int value) throws Exception {
if (size >= maxSize) {
throw new Exception("队列满啦");
}
Node node = new Node(value);
if (size == 0) {
head = node;
tail = node;
} else {
tail.next = node;
tail = node;
}
size++;
}
public int pop() throws Exception {
if (size <= 0) {
throw new Exception("队列空啦");
}
int result = head.val;
head = head.next;
size--;
return result;
}
}
(2)两个栈实现队列
public class MyQueueWithStack {
private MyStack myStack1;
private MyStack myStack2;
public MyQueueWithStack(int size) throws Exception {
myStack1 = new MyStack(size);
myStack2 = new MyStack(size);
}
public void push(int value) throws Exception {
myStack1.push(value);
}
public int pop() throws Exception {
while (!myStack1.isEmpty()) {
myStack2.push(myStack1.pop());
}
int result = myStack2.pop();
while (!myStack2.isEmpty()) {
myStack1.push(myStack2.pop());
}
return result;
}
}
-
测试队列
public class QueueTest { public static void main(String[] args) throws Exception { MyQueue myQueue = new MyQueue(3); myQueue.push(1); myQueue.push(2); myQueue.push(3); System.out.println(myQueue.pop()); System.out.println(myQueue.pop()); System.out.println(myQueue.pop()); MyQueueWithStack myQueueWithStack = new MyQueueWithStack(3); myQueueWithStack.push(1); myQueueWithStack.push(2); myQueueWithStack.push(3); System.out.println(myQueueWithStack.pop()); System.out.println(myQueueWithStack.pop()); System.out.println(myQueueWithStack.pop()); } }
二、二维数据结构
01.二维数组
02.邻接链表
03.拓扑结构-图
04.树
06.链表的递归遍历
public class Test {
public static void printNode(Node node) {
if (node == null) { //递归出口
return;
}
System.out.println(node.getVal()); //对每个节点的通用操作
printNode(node.getNext()); //向下递归点
System.out.println(node.getVal());
}
public static void main(String[] args) {
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(node4);
node4.setNext(node5);
printNode(node1); //1,2,3,4,5,5,4,3,2,1
}
}
07.链表的逆置
public static Node change(Node node) {
if (node.next.next != null) { //如果当前节点不是D
Node result = change(node.next); //将第二个节点传入递归执行
node.next.next = node;
node.next = null;
return result;
} else { //如果当前节点是D节点
Node result = node.next; //得到E节点
node.next.next = node; //E节点指向D节点
node.next = null; //D节点指向null
return result; //将E节点返回
}
}
public static Node change2(Node node) {
Node result = null;
if (node.next.next != null) {
result = change2(node.next);
} else {
result = node.next;
}
node.next.next = node;
node.next = null;
return result;
}
08.栈和队列
public class Test {
public static void main(String[] args) throws Exception {
// MyStack myStack = new MyStack(3); //测试栈
// myStack.push(1);
// myStack.push(2);
// myStack.push(3);
// System.out.println(myStack.pop());
// System.out.println(myStack.pop());
// System.out.println(myStack.pop());
MyQueue myQueue = new MyQueue(3);
myQueue.push(1);
myQueue.push(2);
myQueue.push(3);
System.out.println(myQueue.pop());
System.out.println(myQueue.pop());
System.out.println(myQueue.pop());
System.out.println(myQueue.pop());
}
}
class MyQueue {
Node head = null;
Node tail = null;
int maxSize;
int size;
public MyQueue(int maxSize) {
this.maxSize = maxSize;
this.size = 0;
}
public void push (int val) throws Exception {
Node node = new Node(val);
if (size >= maxSize) {
throw new Exception("队列满了");
}
if (size == 0) {
head = node;
tail = node;
} else {
tail.next = node;
tail = node;
}
size++;
}
public int pop() throws Exception {
if (size <= 0) {
throw new Exception("队列里没数据了");
}
size--;
int result = head.val;
head = head.next;
return result;
}
}
class MyStack {
int[] data;
int top = 0;
public MyStack(int size) {
this.data = new int[size];
}
public void push(int val) throws Exception {
if (top >= this.data.length) {
throw new Exception("栈满了");
}
this.data[top] = val;
top++;
}
public int pop() throws Exception {
if (top <= 0) {
throw new Exception("栈里没数据了");
}
return this.data[--top];
}
public boolean isEmpty() {
if (this.top == 0) {
return true;
} else {
return false;
}
}
}
09.用两个栈模拟队列
class MyQueueWithStack {
MyStack stack1;
MyStack stack2;
public MyQueueWithStack(int size) {
stack1 = new MyStack(size);
stack2 = new MyStack(size);
}
public void push(int val) throws Exception {
stack1.push(val);
}
public int pop() throws Exception {
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
int result = stack2.pop();
while (!stack2.isEmpty()) {
stack1.push(stack2.pop());
}
return result;
}
}
public class Test {
public static void main(String[] args) throws Exception {
MyQueueWithStack myQueueWithStack = new MyQueueWithStack(10);
myQueueWithStack.push(1);
myQueueWithStack.push(2);
myQueueWithStack.push(3);
System.out.println(myQueueWithStack.pop());
System.out.println(myQueueWithStack.pop());
System.out.println(myQueueWithStack.pop());
}
}
10.时间复杂度
假设我们有个数组,我们要查找数组中是否存在某个数。
如何来衡量写的算法效率是否高?
可以用时间吗?不可以
每访问一个元素,时间复杂度记为1。如果一个数组长度为n,如果我们用遍历的方式来进行操作,那么访问n次才能够确定。时间复杂度记为n。
1,N,Log n,N2,N3
11.空间复杂度
用了多少额外的空间,我们暂且估计原始数据的大小为n,我们新开辟的空间是n的多少倍。
12.冒泡排序
//冒泡排序
public class Test {
//排序的本质是什么?
//排序是比较大小,非常错误的
//排序是比较优先级,然后进行位置交换
//在比较大小的时候,例如从小到大排列,数字越小,优先级越高
public static boolean compare(int a, int b) {
if (a > b) {
return true;
}
return false;
}
public static void change(int[] arr, int aIndex, int bIndex) {
int temp = arr[aIndex];
arr[aIndex] = arr[bIndex];
arr[bIndex] = temp;
}
public static void sort(int[] arr) { //边比较边交换
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (compare(arr[j], arr[j + 1])) {
change(arr, j, j + 1);
}
}
}
}
public static void main(String[] args) {
int[] arr = new int[]{2, 4, 3, 1, 9, 0, 6, 7, 8, 5};
sort(arr);
for (int i : arr) {
System.out.println(i);
}
}
}
13.选择排序
public static void sort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
int maxIndex = 0;
for (int j = 1; j < arr.length - i; j++) {
if (compare(arr[j], arr[maxIndex])) {
maxIndex = j;
}
}
change(arr, maxIndex, arr.length - 1 - i);
}
}