一、大O表示法
在对算法的效率衡量时,常采用大O表示法。大O表示法是一种粗略的效率表示法,排除了处理器、编译器不同带来的计算差别,而只与数据项的个数N相关,是一种相对衡量法。例如线性查找的时间为O(N),二分查找为O(log(N))等等。
二、数据结构
1、栈
栈提供了一种后进先出的数据管理方法,提供的操作有压栈(Push)、出栈(Pop)、查看(peek),对栈来说这些操作都只能发生在一个位置——栈顶,也就是最顶层的数据。
实现
public class MyStack {
private int top;
private int[] data;
private int maxSize;
public MyStack(int cap) {
data = new int[cap];
maxSize = cap - 1;
top = -1;
}
public boolean push(int value) {
if(top == maxSize - 1) {
System.out.println("full!");
return false;
} else {
data[++top] = value;
return true;
}
}
public int pop() {
if(top == - 1) {
return -1;
} else {
return data[top--];
}
}
public int peek() {
if(top == -1) {
return -1;
} else {
return data[top];
}
}
}
除了用数组外还可以用链表实现!
2、队列
队列提供了一种先进先出的数据管理方法,提供的操作有插入(insert)和移除(remove),插入操作发生在队头,移除发生在队尾。
实现
public class MyQueue {
private int maxSize;
private int[] queue;
private int head;
private int rear;
public MyQueue(int size) {
maxSize = size + 1;
queue = new int[maxSize];
head = 0;
rear = -1;
}
public boolean insert(int value) {
if(isFull()) {
System.out.println("Full!");
return false;
}
if(rear == maxSize - 1) {
rear = -1;
}
queue[++rear] = value;
return true;
}
public boolean remove() {
if(isEmpty()) {
System.out.println("Empty!");
return false;
}
head++;
if(head == maxSize) {
head = 0;
}
return true;
}
public boolean isEmpty() {
return (rear+1 == head || (head+maxSize-1) == rear);
}
public boolean isFull() {
return (rear+2 == head ||(head+maxSize-2) == rear);
}
}
一般情况下当队尾和队头指向同一个位置时既可以表示队列为空,也可以表示队列已满,因此要区分这两种情况需要进行一些特殊的处理,上面的方法将队列容量扩大了一个元素,然后通过队头和队尾的位置关系来判断empty或者full,这种方式判断的条件比较复杂,还有一种的方式是通过增加一个表示当前数据个数的变量,这样处理起来就简单了。
特殊队列之优先级队列——优先级队列是队列中的一种特殊情况,队列中的数据项根据一定的规则进行排序,所以是一种有序队列,这样在插入的时候就需要先与队中各项进行一次比较来确定位置。
3、链表
链表是线性表中的一种,那什么是线性表呢?线性表是最简单的一种数据结构,这种结构中的数据首尾相接,每个数据向前或向后只能连接一个数据。线性表分为顺序表和链表,顺序表即最常用的数组,数据一个挨一个,通过下标访问,数据之间没有明显的关系;而链表则将数据依次链接起来,通过前一个可以找到后一个,就像一条锁链一样。链表中数据的基本单位是一个数据块,称为链结点,其中包含了要存储的用户数据和下一个数据块的引用(指针)。
链表又可以分为单向链表和双向链表。
3.1单向链表
单向链表的指定了链的查找方向只能朝一个方向,即只能通过前一个数据找到后一个数据,而不能通过后一个找到前一个。单向链表提供的操作有插入、删除、查找等。
实现
首先定义链结点
public class MyLink {
int data;
MyLink next;
public MyLink(int value) {
data = value;
}
public void displayLink() {
System.out.println("LinkData->" + data);
}
}
再定义单向链表
public class MyLinkList {
private MyLink first;
public MyLinkList() {
first = null;
}
public void insertFirst(int value) {
MyLink newLink = new MyLink(value);
newLink.next = first;
first = newLink;
}
public int deletFirst() {
if(first == null) {
System.out.println("empty!");
return -1;
} else {
MyLink temp = first;
first = first.next;
return temp.data;
}
}
public boolean find(int value) {
MyLink current = first;
while(current != null) {
if(current.data == value) {
return true;
} else {
current = current.next;
}
}
return false;
}
public boolean delet(int value) {
MyLink current = first;
MyLink previous = first;
while(current!=null) {
if(current.data == value) {
previous.next = current.next;
return true;
} else {
previous = current;
current = current.next;
}
}
return false;
}
public void displayList() {
MyLink current = first;
while(current != null) {
current.displayLink();
current = current.next;
}
}
}
这个单向链表中通过first指向链表的起始位置,这样数据每次只能添加在最前端,如果想在链的最后也添加数据,可以再定义一个指向链末尾的引用last就可以实现。单向链表只能实现链的单向遍历,如果要双向遍历,就需要下面的数据结构——双向链表!
3.2 双向链表
双向链表对单向链表进行了扩展,支持逆向遍历,数据的查找也更加方便,但是因为增加了一个向前的指向,所以存储的内容就多了一项。
实现
链结点
public class MyDoubleLink {
int data;
MyDoubleLink previous;
MyDoubleLink next;
public MyDoubleLink(int value) {
data = value;
}
public void displayLink() {
System.out.println("doubleLink-->" + data);
}
}
双向链表
public class MyDoubleLinkList {
private MyDoubleLink first;
private MyDoubleLink last;
public MyDoubleLinkList() {
first = null;
last = null;
}
public void insertFirst(int value) {
MyDoubleLink newLink = new MyDoubleLink(value);
if(first == null) {
last = newLink;
} else {
first.previous = newLink;
newLink.next = first;
}
first = newLink;
}
public void insertLast(int value) {
MyDoubleLink newLink = new MyDoubleLink(value);
if(last == null) {
first = newLink;
} else {
last.next = newLink;
newLink.previous = last;
}
last = newLink;
}
public int deletFirst() {
if(first == null) {
System.out.println("empty!")
return -1;
}
MyDoubleLink temp = first;
if(first.next == null) {
last = null;
} else {
first.next.previous = null;
}
first = first.next;
return temp.data;
}
public int deletLast() {
if(last == null) {
return -1;
}
MyDoubleLink temp;
if(last.previous == null) {
first = null;
} else {
last.previous.next = null;
}
last = last.previous;
return last.data;
}
public boolean delet(int value) {
if(first == null) {
return false;
}
MyDoubleLink current = first;
while(current.data != value) {
current = current.next;
if(current == null)
return false;
}
if(current == first) {
first = current.next;
} else {
current.previous.next = current.next;
}
if(current == last) {
last = current.previous;
} else {
current.next.previous = current.previous;
}
return true;
}
public void displayList() {
MyDoubleLink current = first;
while(current!=null) {
current.displayLink();
current = current.next;
}
}
}
这里在删除某一具体的项时从最开始往下遍历直到找到目标,想了一下其实还可以从两头同时找,关键在于当两头遍历相交时的判断条件,如果节点是基数个的话直接可以判断(first == last),偶数的话就要添加辅助条件了,比如数据项的个数什么的。
3.3链表实现的栈和队列
栈
链结点使用单链表的链结点MyLink;
public class MyStackL {
MyLink top;
public MyStackL() {
top = null;
}
public void push(int value) {
MyLink link = new MyLink(value);
link.next = top;
top = link;
}
public int pop() {
if(top == null) {
System.out.println("empty!");
return -1;
} else {
int temp = top.data;
top = top.next;
return temp;
}
}
public int peep() {
if(top == null) {
System.out.println("empty!");
return -1;
} else {
return top.data;
}
}
public void displayStack() {
MyLink temp = top;
while(temp != null) {
temp.displayLink();
temp = temp.next;
}
}
}
从上面的实现可以看出使用链表的栈实现相对简单,因为链表不用担心容量的问题。
队列
public class MyQueueL {
private MyLink head;
private MyLink rear;
public MyQueueL() {
head = null;
rear = null;
}
public void add(int value) {
MyLink link = new MyLink(value);
if(head == null) {
head = link;
} else {
rear.next = link;
}
rear = link;
}
public int remove() {
if(head == null) {
System.out.println("empty!");
return -1;
}
MyLink temp = head;
head = head.next;
return temp.data;
}
public boolean isEmpty() {
return head == null;
}
public void displayQueue() {
MyLink temp = head;
while(temp != null) {
temp.displayLink();
temp = temp.next;
}
}
}