线性表
由零个或多个组成的有限序列。首先他需要是序列,当元素有多个的时候,第一元素无前驱,最后一个元素无后继,其余每个元素都有唯一的前驱和后继。线性表中每个数据元素可以由若干个数据项组成。
线性表的顺序存储
用一段连续的存储单元,依次存储线性表中的数据元素。
线性表顺序存储结构:
#define MAXSIZE 20 /*存储空间初始分配*/
#define ERROR 0
#define OK 1
typedef int ElemType; /*定义数据类型,具体以实际情况*/
typedef struct{
ElemType data[MAXSIZE]; /*使用数据存储线性表*/
int length; /*线性表当前的长度*/
}
线性表查找
int GetElem(SqList *L,int i, ElemType e){
if( L.length ==0 || i >L.length || i<1)
return ERROR;
e = L.data[i-1];
return OK;
}
时间复杂度O(1)
线性表插入
int InserList(SqList *L,int i,ElemType e){
int k;
if( L->length >= MASIZE ) /*当前长度大于数组规定长度*/
return ERROR;
if( i <1 || i > L->legth+1) /*插入位置不合理*/
return ERROR;
if(i<=L->length){
for(k=L->length-1;k>i-1;k--){
L->data[k+1] = L->data[k]; /*将位置k后的元素全部向后移动一位*/
}
L->data[i-1] = e; /*将插入的值放入第i位,下标为i-1*/
L->length++; /*当前线性表长度加1*/
return OK;
}
}
时间复杂度为O(n)
线性表删除
int DeleteList(SqList *L,int i,ElemType e){
int k;
if(L->length == 0) /*判断线性表是否有元素*/
return ERROR;
if(i<1 || i > L->length) /*判断删除位置是否合理*/
return ERROR;
e = L->data[i-1];
if(i<L->length){
for(k=i;k<L->length;k++){ /*将第i个元素之后的所有元素向前移动一个单位*/
L->data[i-1] = L->data[i];
}
}
L->length--;
return OK;
}
时间复杂度O(n)
线性表的链式存储
用一组任意的存储单元存储线性表的数据元素,这写存储单元可以是连续的也可以是不连续的,每个节点除了存储数据外,还存储指向下一个节点地址。如果每个节点同时存储前一个节点的地址信息,则称为双向链表。
线性表单链表存储结构:
#define ERROR 0
#define OK 1
typedef int ElemType; /* 假设ElemType类型为intt*/
typedef struct Node{
ElemType data;
struct Node *next;
}Node;
typedef struct Node *LinkList; /*定义LinkList */
单链表的创建:
头插法:
void CreateListHead(LinkList *L,int n){
int i;
LinkList p; /*每次新节点*/
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = null; /*建立带表头节点的单链表*/
for(i=0;i<n;i++){
p = (LinkList)malloc(sizeof(Node));
p->data = i; /*根据实际情况存储数据*/
p->next = (*L)->next;
(*L)->next = p;
}
}
时间复杂度O(n)
尾插法:
void CreateListTail(LinkList *L,int n){
int i;
LinkList p,r;
*L = (LinkList)malloc(sizeof(Node));
r = *L;
for(i=0;i<n;i++){
p = (LinkList)malloc(sizeof(Node)); /*生成新节点*/
p->data = i; /*新节点存储数据*/
r->next = p; /*将表尾节点指向新节点*/
r = p; /*将新节点定义为表尾节点*/
}
r->next = null; /*表示当前链表已经创建完毕*/
}
时间复杂度O(n)
单链表读取
int GetElem(LinkList *L,int i,ElemType e){
int j;
LinkList p;
p = (*L)->next; /*让p指向第一个节点*/
while(p && j<i){ /*这里因为之前是让p指向第一个节点,所以这里到达i-1时候,p已经为第i个节点了*/
p = p->next;
j++;
}
if(!p || j>i) /*判断是否存在*/
return ERROR;
e = p->data;
return OK;
}
时间复杂度O(n)
单链表插入
int ListInsert(LinkList *L,int i,ElemType e){
int j;
LinkList p,q;
p = *L; /*这里是将链表头指针赋给p,即在循环中,第一次是指向第一个节点,所以到i-1时,正处在i-1节点*
while(p && j<i){ /*这里是将*/
p = p->next;
j++;
}
if(!p || j>i){
return ERROR;
}
q = (LinkList)malloc(sizeof(Node));
q->data = e;
q->next = p->next; /*一定要现将新节点指针指向i节点,然后在将i-1节点指向新节点*/
p->next = q;
return OK;
}
单链表删除
int ListDelete(LinkList *L,int i,ElemType e){
int j;
LinkList p,q;
p = *L;
while(p && j<i){
p = p->next;
j++;
}
if(!p || j>i)
return ERROR;
q = p->next; /*将要删除的i节点赋给q*/
p->next=q->next; /*是i-1节点指向i+1节点*/
e = q->data; /*获取要删除节点的data*/
free(q);
return OK;
}
对于单链表的插入删除,如果不知道要删除的位置指针,也需要遍历链表,但是如果无论插入删除多少个只需扫描一次即可,其他时候的时间复杂度是O(1)
单链表销毁
int ClearList(LinkList *L){
LinkList p;
p=(*L)->next; /*使p指向第一个节点*/
while(p){ /*判断到没到表尾*/
q=p->next; /*将q指向下一个节点*/
free(p); /*删除当前节点*/
p=q; /*p指向下一个要删除的节点*/
}
p->next=null;
return OK;
}
基于JAVA实现线性表
首先要了解java集合中Collection中的方法:http://blog.youkuaiyun.com/colin_yjz/article/details/46673383
Collection以及Collection的实现类都实现了Iterable接口,用以使用增强的for循环。并且都提供了iterator方法,返回一个Iterator类型的对象,iterator用来对数据元素进行迭代。关于Iterator与Iterable的区别可以看:http://blog.youkuaiyun.com/colin_yjz/article/details/46673275
线性表使用List中的ArrayList和LinkList来实现最佳。ArrayList是一种可增长的数组的实现,对于随机访问花费时间数量级是常数,缺点是插入和删除代价非常高,因为要移动大量的元素。LinkList则提供了ListADT的双链表实现,对于插入和删除都是常数数量级,但是get查找效率非常低。操作线性表应该尽量使用Iterator迭代器,这样效率比使用循环效率高,对于删除等操作应该使用Iterator中提供的remove,因为迭代器的remove不会影响Iterator结构,如果使用List的remove会影响Iterator结构,从而删除失败。
对于二者List提供了ListIterator,有previous和hasPrevious方法支持向前遍历。并且Add操作的是当前项,即迭代的previous和next之间。
线性表使用java实现可以查看博主的ArrayList源码解析博文,因为比较简单,所以没有手敲实现。
链表java实现,:
public class MyLinkList<E> {
Node<E> first; //链表头节点
Node<E> last; //链表尾节点
int size = 0; //链表节点个数
/**
* 内部静态类,封装节点信息(无外围类引用,可以声明一个静态类,以便消除产生的引用)
* pref:前一节点
* next:后一节点、
* data:存储数据区
*/
private static class Node<E>{
E data;
Node<E> next;
Node<E> pref;
Node(Node<E> pref,E data,Node<E> next){
this.pref = pref;
this.data = data;
this.next = next;
}
}
/**
* 两个构造方法,无参构造方法用来初始化空链表,有参构造方法,将集合中元素初始化到链表中
*/
public MyLinkList(){
}
public MyLinkList(Collection<? extends E> c) throws Exception{
this();
addAll(c);
}
void linkLast(E e){
Node<E> l = last; //暂存尾节点
Node<E> newNode = new Node<E>(l, e, null); //创建一个新节点
last = newNode; //将指向尾节点的变量,指向新节点
if(l == null)
first = newNode; //如果尾节点为空,说明头节点也为null,将头节点也要指向newNode
else
l.next = newNode; //将之前尾节点指向后一节点区指向新添加的节点
size++;
}
public boolean add(E e){
linkLast(e);
return true;
}
/**
* 返回指定位置节点
* @param index
* @return
*/
Node<E> node(int index){
Node<E> x = first;
for(int i=0;i<index;i++){
x = x.next;
}
return x;
}
/**
* 检查索引位置是否合法
* @param index
* @throws Exception
*/
void checkIndex(int index) throws Exception{
if(index<0||index>size){
throw new Exception("index error");
}
}
/**
* 在非尾节点前添加一个节点
* @param e
* @param now
*/
void linkBefor(E e,Node<E> now){
Node<E> p = now.pref;
Node<E> newNode = new Node<E>(p, e, now);
if(p == null){
first = newNode;
}
else{
p.next = newNode;
}
now.pref =newNode;
}
/**
* 在指定位置添加元素
*/
public void add(int index,E e) throws Exception{
checkIndex(index);
if(index == size)
linkLast(e);
else
linkBefor(e, node(index));
}
/**
* 将集合元素添加到链表中,他默认也是调用重载方法addAll(index,c),只是在表尾添加
* @param c
* @throws Exception
*/
public boolean addAll(Collection<? extends E> c) throws Exception{
return addAll(size,c);
}
public boolean addAll(int index,Collection<? extends E > c) throws Exception{
checkIndex(index);
Node<E> pred; //要插入节点位置的前一个节点
Node<E> now; //要好插入的节点位置
Object[] o = c.toArray();
int newNum = o.length;
if(newNum == 0)
return false;
if(index == size){ //根据位置查找pred节点和now节点
pred = last;
now = null;
}else{
now = node(index);
pred = now.pref;
}
for (Object oc : o) {
@SuppressWarnings("unchecked")
E e = (E) oc;
Node<E> newNode = new Node<E>(pred, e, null);
if(pred == null) //如果插入前一个节点是null说明现在插入的位置是链表头部,需要将头节点指向当前插入及诶单
first = newNode;
else
pred.next = newNode; //将前一节点指向后节点的指针指向新节点
pred = newNode;
}
if(now == null){ //如果当前插入节点位置是null,说明在尾部添加的节点,需要将尾节点指向
last = pred;
}else{
pred.next = now;
now.pref = pred;
}
size += newNum;
return true;
}
/*
* 在表头插入元素
*/
public void addFirst(E e){
linkBefor(e, first);
}
/*
* 在表尾添加元素
*/
public void addLast(E e){
linkLast(e);
}
/**
*清空链表中所有元素
*/
public void clear(){
Node<E> x = first;
Node<E> temp = null;
for(int i=0;i<size;i++){
temp = x.next;
x.data = null;
x.next = null;
x.pref = null;
x = temp;
}
size = 0;
first = last = null;
}
/**
* 查找指定元素的位置
*/
public int indexOf(Object o){
Node<E> x = first;
if( o == null){ //null比较与其他比较不同
for(int i =0 ;i<size;i++){
if(x.data == null){
return i;
}
x = x.next;
}
}
else{
for(int i=0;i<size;i++){
if(o.equals(x.data)){
return i;
}
x = x.next;
}
}
return -1; //如果没有找到返回-1
}
/**
* 判断是否包含一个指定元素,就是判断其位置
*/
public boolean contains(Object o){
return indexOf(o) != -1;
}
/**
*获取指定位置元素
* @throws Exception
*/
public E get(int index) throws Exception{
checkIndex(index);
return node(index).data;
}
/**
* 删除表头元素
*/
public E removeFirst(){
Node<E> f = first;
Node<E> next = f.next;
E element = f.data;
f.data = null;
f.next = null;
first = next;
if(next == null)
last = null;
else
next.pref = null;
size--;
return element;
}
/**
* 删除表尾元素
*/
public E removeLast(){
Node<E> t = last;
Node<E> p = last.pref;
E element = t.data;
t.data = null;
t.pref = null;
last = p;
if(p == null)
first = null;
else
p.next = null;
size--;
return element;
}
/**
* 删除指定元素
*/
public boolean remove(Object o){
Node<E> x = first;
int index = -1;
if(o == null){
for(int i =0;i<size;i++){
if(x.data == null){
index = i;
}
x = x.next;
}
}else{
for(int i=0;i<size;i++){
if(o.equals(x.data)){
index = i;
}
x = x.next;
}
}
if(index == -1){
return false;
}else{
Node<E> now = node(index);
Node<E> p = now.pref;
Node<E> n = now.next;
if(p == null){
first = n;
}else{
p.next = n;
now.pref = null;
}
if(n == null){
last = p;
}else{
n.pref = p;
now.next = null;
}
now.data = null;
size--;
return true;
}
}
/**
* 修改指定位置元素
* @throws Exception
*/
public E set(int index,E element) throws Exception{
checkIndex(index);
Node<E> x = node(index);
E oldEle = x.data;
x.data = element;
return oldEle;
}
}