Comparable接口
demo:
public class Student implements Comparable<Student> {
private int num;
private String name;
public Student(int num, String name) {
this.num = num;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"num=" + num +
", name='" + name + '\'' +
'}';
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Student o) {
return this.getNum()-o.num;
}
}
public class TestComparable {
public static void main(String args[]){
Student student1 = new Student(10,"a");
Student student2 = new Student(11,"b");
System.out.println(getMax(student1,student2));
}
private static Comparable getMax(Comparable a,Comparable b){
int result=a.compareTo(b);
if (result>=0){
return a;
}else{
return b;
}
}
}
Student类通过实现接口来完成比较的功能
在测试类中,运用compareTo方法实现求较大值的功能
冒泡排序
demo:
public class Bubble {
public static void sort(Comparable[] a){
for (int i=a.length-1;i>0;i--){
for (int j=0;j<i;j++){
if(greater(a[j],a[j+1])){
exch(a,j,j+1);
}
}
}
}
private static boolean greater(Comparable a,Comparable b){
return a.compareTo(b)>0;
}
private static void exch(Comparable []a,int i,int j){
Comparable temp;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
public class BubbleTest {
public static void main(String[] args) {
Integer a[]={0,9,8,7,-1,40};
Bubble.sort(a);
System.out.println(Arrays.toString(a));
}
}
在Bubble类中,有三个基本方法
sort
两次for循环,完成排序
greater
求得较大的一个
exch
交换两个数组变量的存放顺序
在BubbleTest类中运用Bubble.sort方法实现对数组的排序
冒泡排序的原理:
进行a.length-1次循环,每次循环,相邻元素比较,若不符合排序规则,交换位置,该次循环过后,数组中最大元素移动到最尾端
逐次循环过后,排序完成
冒泡排序的时间复杂度分析:
O(n^2)
选择排序
demo:
public class Selection {
public static void sort(Comparable[] a){
for(int i=0;i<a.length-2;i++){
int minIndex=i;
for (int j=i+1;j<a.length;j++){
if(greater(a[minIndex],a[j])){
minIndex=j;
}
}
exch(a,i,minIndex);
}
}
private static boolean greater(Comparable a,Comparable b){
return a.compareTo(b)>0;
}
private static void exch(Comparable []a,int i,int j){
Comparable temp;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
插入排序的原理是:
进行a.length-1次循环
每次循环假定i为最小元素的下表,将其之后的元素逐次和a[i]比较,得到该次循环的最小下表,在每次循环中都要将循环结束得到的最小下表对应的元素放到该次循环的起始位置i
经过a.length-1次循环,排序结束,元素按从小到大排序
插入排序的时间复杂度分析:
O(n^2)
插入排序
demo:
public class Insertion {
public static void sort(Comparable[] a) {
for (int i = 1; i<a.length; i++) {
for (int j=i;j>0;j--){
if (greater(a[j-1],a[j])){
exch(a,j-1,j);
}else {
break;
}
}
}
}
private static boolean greater(Comparable a,Comparable b){
return a.compareTo(b)>0;
}
private static void exch(Comparable []a,int i,int j){
Comparable temp;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
插入排序的原理:
进行a.length-1次循环,是由数组第二个元素开始的循环,每次循环的任务是将当前元素插入到该元素之前的数组中合适的位置(若是比前一个元素大,则直接break该次循环,即已经处在正确的位置,若是比前一个元素小,则继续向前比较,直至到达合适的位置)
循环结束,排序结束
插入排序的时间复杂度:
O(n^2)
以上三种排序(冒泡排序/选择排序/插入排序),都是基础排序,时间复杂度皆为O(n^2)
希尔排序
demo:
public class Shell {
public static void sort(Comparable[] a){
int h=1;
while(h<a.length/2){
h=2*h+1;
}
while (h>=1){
for (int i=h;i<a.length;i++){
for (int j=i;j>=h;j-=h){
if(greater(a[j-h],a[j])){
exch(a,j-h,j);
}else {
break;
}
}
}
h=h/2;
}
}
private static boolean greater(Comparable a,Comparable b){
return a.compareTo(b)>0;
}
private static void exch(Comparable []a,int i,int j){
Comparable temp;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
希尔排序的原理:
在插入排序的基础上进行改良
首先获取增长量h
目的是对数组整体进行分组
h取第一个值
进行循环,按照a[j]与a[j-h]为一组,进行插排,完成后
h继续取值进行循环
希尔排序的时间复杂度:
事后分析法,获取时间差进行分析;
归并排序
快速排序
demo:
public class Quick {
private static boolean less(Comparable a,Comparable b){
return a.compareTo(b)<0;
}
private static void exch(Comparable []a,int i,int j){
Comparable temp;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
public static int partition(Comparable[] a,int lo,int hi){
Comparable key=a[lo];
int left=lo;
int right=hi+1;
while (true){
while (less(key,a[--right])){
if(right==lo){
break;
}
}
while (less(a[++left],key)){
if (left==hi){
break;
}
}
if (left>=right){
break;
}else {
exch(a,left,right);
}
}
exch(a,lo,right);
return right;
}
public static void sort(Comparable[] a){
int lo=0;
int hi=a.length-1;
sort(a,lo,hi);
}
private static void sort(Comparable[] a,int lo,int hi){
if (hi<=lo){
return;
}
int partition = partition(a, lo, hi);
sort(a,lo,partition-1);
sort(a,partition+1,hi);
}
}
快速排序时间复杂度:
最优情况–O(nlogn)
最坏情况–O(n^2)
6种排序实现原理
排序稳定性比较
稳定性是指 AB元素值相等 A元素原本在B元素的前面 排序过后二者相对位置不变
稳定:
冒泡排序|插入排序|归并排序
不稳定:
选择排序|希尔排序|快速排序
顺序表
自己实现一个顺序表:
首先要明确泛型,顺序表中存储的元素的类型。
顺序表中有两个内部私有变量:
1长度
2数组
提供一个传入长度N的构造方法(即构建了一个长度为N的数组)
顺序表实现的方法:
清除全部元素
判断表中是否为空
求取表长
得到指定位置的元素
在表尾插入元素
在指定位置插入元素
移除指定位置的元素
求指定元素的位置
由于线性表底层采用数组实现,在创建线性表时,需指定线性表的长度,导致,后续进行增删操作时,出现元素溢出、空间浪费等问题
在对线性表增删时,对线性表进行扩容、减容,可避免上述问题
创建一个修改线性表容量的方法
当执行插入方法时,判断表中存在元素是否已经达到数组最大容量,如果已达到,将数组容量翻倍。
当执行删除操作时,判断表中元素,是否已经是数组容量的1/4,如果是,则将数组容量缩小至1/4
实现外部对线性表的遍历
线性表要实现Iterable接口,并重写iterator方法(该方法返回一个Iterator,需要自己写一个继承自Iterator的迭代器)
链表(单链表,双向链表,循环链表)
首先明确泛型,链表中存储的元素的类型。
链表中有两个内部私有变量:
1长度
2头指针节点
链表中有一个内部类Node
提供一个无参数的构造方法,初始化长度,初始化头指针节点
链表实现的方法:
清除全部元素
判断表中是否为空
求取表长
得到指定位置的元素
在表尾插入元素
在指定位置插入元素
移除指定位置的元素
求指定元素的位置
反转链表
实现外部对链表的遍历
链表要实现Iterable接口,并重写iterator方法(该方法返回一个Iterator,需要自己写一个继承自Iterator的迭代器)
快慢指针
1.解决中间值问题,新建两个指针,慢指针步长为1,快指针步长为2,快指针遍历结束,慢指针恰好处于中间
2检验单链表是否有环,建立循环,当快慢指针相遇时代表有环
3寻找有环链表的入口:
当快慢指针相遇后,表明链表中有环,重新设定一个新指针在链表的起点,步长与慢指针相同,当慢指针与新指针相遇时,所指位置即环的入口
栈
首先明确泛型,栈中存储的元素的类型。
栈中有两个内部私有变量:
1长度
2头指针节点
栈中有一个内部类Node
提供一个无参数的构造方法,初始化长度,初始化头指针节点
栈提供的方法:
判断栈中是否为空
求取栈的长度
push,将新元素推入栈中(即将新元素置于head后)
pop,将栈顶元素取出(即将head后元素取出)
实现外部对栈的遍历
链表要实现Iterable接口,并重写iterator方法(该方法返回一个Iterator,需要自己写一个继承自Iterator的迭代器)
括号匹配问题
建立一个栈,对字符串进行遍历,遇到左括号,将其压入栈中,遇到右括号,弹出栈顶元素。循环结束判断栈中元素是否为空,从而判断是否匹配成功
逆波兰式问题
建立一个栈,对逆波兰表达式字符串进行遍历,遇到数字将其压入栈中,遇到字符串,弹出栈顶两个元素进行运算,并将结果推入栈中,循环结束后,栈中仅存一个元素即为运算结果
队列
首先明确泛型,队列中存储的元素的类型。
队列中有3个内部私有变量:
1长度
2头指针节点
3尾结点
队列中有一个内部类Node
提供一个无参数的构造方法,初始化长度,初始化头指针节点,初始化尾结点为空
队列提供的方法:
判断队列中是否为空
求取队列的长度
入队:加至尾结点之后
出队:取头指针的下一节点
实现外部对队列的遍历
链表要实现Iterable接口,并重写iterator方法(该方法返回一个Iterator,需要自己写一个继承自Iterator的迭代器)
树|二叉树
首先明确泛型,二叉树中存储的<KEY,VALUE>的类型。
二叉树中有2个内部私有变量:
1节点数量
2根节点
二叉树中有一个内部类Node
Node中有4个内部变量,key,value,左子节点,右子节点
二叉树提供的方法:
求取二叉树节点数目
放入元素
根据key求得value值
根据value值求得key
求最大/最小key
删除指定元素
求二叉树最大深度
前序/中序/后序/层序遍历二叉树