大概有十几天没写博客了,没人看也是很伤心的,TAT。大三对计算机考研的内容由了一定的了解。并且:算法+数据结构=程序。所以想重新学习数据结构,不多说,入正题。
线性表
线性表是由n(n>=0)个数据元素所构成的有限序列,通常表示为(a0,a1,…,ai,…an-1)。
线性表有两种基本形式:顺序表和链表(链表有多种形式),他们各有各的特点。当线性表的长度变化比较大或者难以估计,宜用链表。但在长度可以预计并且变化较小的话,宜用顺序表。对线性表按序号访问数据元素时,顺序表要优于链表。在线性表做插入和删除操作时,链表要优于顺序表。所以对顺序表和单链表的选择,视实际情况而定。
线性表的数据接口(Java)应包含如下方法(主要):
public interface List {
public void clear(); //清空
public boolean isEmpty();//判断线性表是否为空
public int length();//返回线性表的长度
public Object get(int i) throws Exception;//返回第i个元素
public void insert(int i,Object x) throws Exception;
public void insert(Object x) throws Exception; //尾插入
public void remove(int i) throws Exception;//删除第i个元素
public int indexOf(Object x);//查找x元素
public void display();//输出各个元素的值
}
顺序表
顺序表中的元素是在数组中保存的,初始化后空间存储大小是一定的,所以在插入中增加了扩容方法(如果元素再插入要溢出)
package gzy;
public class SqList implements List{
private Object[] element; //顺序表元素存储位置
private int curLen; //顺序表的长度
public SqList(int size){
element=new Object[size];
curLen=0;
}
@Override
public void clear() {
curLen=0;
}
@Override
public boolean isEmpty() {
return curLen==0;
}
@Override
public int length() {
return curLen;
}
public Object get(int i) throws Exception {
if(i<0||i>curLen)
throw new Exception("第"+i+"个元素不存在");
return element[i];
}
@Override
public void insert(int i, Object x) throws Exception{
if(curLen==element.length){ //扩容
Object[] listElem=element;
element=new Object[curLen+1];
for(int j=0;j<listElem.length;j++)
element[j]=listElem[j];
}
if(i<0||i>curLen){
throw new Exception("i位置不合法");
}
for(int k=curLen;k>i;k--)
element[k]=element[k-1];
element[i]=x;
curLen++;
}
@Override
public void insert(Object x) throws Exception{
insert(curLen,x);
}
@Override
public void remove(int i) throws Exception{
if(i<0||i>curLen)
throw new Exception("i的位置不合法");
for(int j=i;j<curLen-1;j++)
element[j]=element[j+1];
curLen--;
}
@Override
public int indexOf(Object x) {
for(int i=0;i<curLen;i++){
if(element[i].equals(x))
return i;
}
return-1;
}
@Override
public void display() {
for(int i=0;i<curLen;i++)
System.out.print(element[i]+" ");
System.out.println();
}
}
单链表
单链表中需要一个结点类(当然你完全可以直接把结点类当成一个链表)
并且需要一个头结点:头结点的好处是在插入中不需要分情况进行判断
package gzy;
//结点类
class Node{
public Object data;
public Node next;
public Node(){
this.data=null;
this.next=null;
}
public Node(Object data){
this.data=data;
this.next=null;
}
public Node(Object data,Node next){
this.data=data;
this.next=next;
}
}
public class LinkedList implements List{
Node head; //头结点
public LinkedList(){
this.head=new Node();
}
@Override
public void clear() {
this.head=null;
}
@Override
public boolean isEmpty() {
return this.head.next==null;
}
@Override
public int length() {
int l=0;
Node p=head.next;
while(p!=null){
l++;
p=p.next;
}
return l;
}
@Override
public Object get(int i) throws Exception {
int j=0;
Node p=head.next;
while(p!=null&&j<i){
p=p.next;
j++;
}
if(i!=j)
throw new Exception("第"+i+"个元素不存在");
return p.data;
}
@Override
public void insert(int i, Object x) throws Exception {
Node p=head;
int j=0;
//寻找前驱结点
while(p.next!=null&&j<i){
p=p.next;
j++;
}
if(i!=j)
throw new Exception("插入位置不合法");
p.next=new Node(x,p.next);
}
@Override
public void insert(Object x) throws Exception {
insert(this.length(),x);
}
@Override
public void remove(int i) throws Exception {
int j=0;
Node p=head;
while(p.next!=null&&j<i){
p=p.next;
j++;
}
if(i!=j)
throw new Exception("删除位置不合法");
p.next=p.next.next;
}
@Override
public int indexOf(Object x) {
int j=0;
Node p=head.next;
while(p!=null&&!p.data.equals(x)){
p=p.next;
j++;
}
if(p!=null)
return j;
return -1;
}
@Override
public void display() {
Node p=head.next;
while(p!=null){
System.out.print(p.data+" ");
p=p.next;
}
System.out.println();
}
}
单链表的种类有很多,(循环单链表,双链表,循环双链表),此处在举一个循环单链表的例子
循环单链表
在实现循环链表时,可以使用头或尾指针去标识它。因为尾指针访问头尾结点时间复杂度都为O(1),所以实际中,仅仅使用尾指针来标识。此处合并两个循环单链表使用了尾指针,时间复杂度为O(1)。
package gzy;
public class CircularList implements List{
Node head;
public CircularList(){
head=new Node();
head.next=head;
}
@Override
public void clear() {
head.next=head;
}
@Override
public boolean isEmpty() {
return this.head.next==head;
}
@Override
public int length() {
int l=0;
Node p=head.next;
while(p!=head){
l++;
p=p.next;
}
return l;
}
@Override
public Object get(int i) throws Exception {
while(i<0||i>this.length()-1)
throw new Exception("i位置不符合");
int j=0;
Node p=head.next;
while(j<i){
p=p.next;
j++;
}
return p.data;
}
@Override
public void insert(int i, Object x) throws Exception {
while(i<0||i>this.length())
throw new Exception("插入位置不符合");
Node p=head;
int j=0;
//寻找前驱结点
while(j<i){
p=p.next;
j++;
}
p.next=new Node(x,p.next);
}
@Override
public void insert(Object x) throws Exception {
insert(this.length(),x);
}
@Override
public void remove(int i) throws Exception {
int j=0;
Node p=head;
while(p.next!=head&&j<i){
p=p.next;
j++;
}
if(i!=j)
throw new Exception("删除位置不合法");
p.next=p.next.next;
}
@Override
public int indexOf(Object x) {
int j=0;
Node p=head.next;
while(p!=head&&!p.data.equals(x)){
p=p.next;
j++;
}
if(p!=head)
return j;
return -1;
}
@Override
public void display() {
Node p=head.next;
while(p!=head){
System.out.print(p.data+" ");
p=p.next;
}
System.out.println();
}
public Node getLastNode(){
Node p=head.next;
while(p.next!=head)
p=p.next;
return p;
}
public void merge(CircularList list){
this.getLastNode().next=list.head.next;
list.getLastNode().next=this.head;
}
}