線性表
由零個或多個組成的有限序列。首先他需要是序列,當元素有多個的時候,第一元素無前驅,最後一個元素無後繼,其餘每個元素都有唯一的前驅和後繼。線性表中每個數據元素可以由若干個數據項組成。
線性表的順序存儲
用一段連續的存儲單元,依次存儲線性表中的數據元素。
線性表順序存儲結構:
#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;
}
}