在对算法的效率衡量时,常采用大O表示法。大O表示法是一种粗略的效率表示法,排除了处理器、编译器不同带来的计算差别,而只与数据项的个数N相关,是一种相对衡量法。例如线性查找的时间为O(N),二分查找为O(log(N))等等。
栈提供了一种后进先出的数据管理方法,提供的操作有压栈(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]; } } }
除了用数组外还可以用链表实现!
队列提供了一种先进先出的数据管理方法,提供的操作有插入(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.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; } } }