数据结构—线性表(Java、C双语言实现)

线性表

由零个或多个组成的有限序列。首先他需要是序列,当元素有多个的时候,第一元素无前驱,最后一个元素无后继,其余每个元素都有唯一的前驱和后继。线性表中每个数据元素可以由若干个数据项组成。

线性表的顺序存储

用一段连续的存储单元,依次存储线性表中的数据元素。

线性表顺序存储结构:

#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.csdn.net/colin_yjz/article/details/46673383

Collection以及Collection的实现类都实现了Iterable接口,用以使用增强的for循环。并且都提供了iterator方法,返回一个Iterator类型的对象,iterator用来对数据元素进行迭代。关于Iterator与Iterable的区别可以看:http://blog.csdn.net/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;
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章