数据结构知识整理(一)

一、大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;
		}
	}
}


你可能感兴趣的:(数据结构知识整理(一))