前面兩篇文章我已經把線性表的順序儲存和鏈式儲存都實現了一次,還記得學資料結構的時候,看著老師給的代碼,覺得操作很簡單,自己再實現一次的時候,發現還是有很多需要考慮周全的。
我們一直都是建立的有頭結點的鏈表,因為有頭結點的鏈表在操作起來很方便,尤其是在一些邊界處理上,不容易出錯,而且關鍵是比較好理解。無頭結點的單鏈表相比起來在邊界的處理上稍微要複雜一些了,容易出現錯誤,代碼也要難理解一些。我是在有頭結點的單鏈表上進行修改,添加了利用頭插法和尾插法建立鏈表的函數,保留了原來的在特定位置插入新結點的函數,實現了一個無頭結點的單鏈表,以前覺得很簡單,真正做下去才發現沒有頭結點的單鏈表,在很多情況下都無法很好的實現對其統一操作,特別是在刪除、插入等的操作上,需要細心。代碼奉上,大家相互學習
/**用頭插法與尾插法實現了無頭結點單鏈表的建立*資料結構<三>*鏈式儲存線性表(無前端節點)*/#include <iostream>#include <stdlib.h>using namespace std;typedef int ElemType;typedef struct LNode{ElemType data;struct LNode *next;}LNode,*LinkList;//LNode 結構體類型,LinkList 結構體指標類型//構造一個空的線性表int InitList(LinkList &L){L=(LinkList)malloc(sizeof(LNode));//head為頭指標if(!L)return 1;L=NULL;return 0;}//銷毀線性表線性表void DestroyList(LinkList &L){LinkList p;if(L!=NULL)while (L->next!=NULL){p=L->next;L->next=L->next->next;free(p);//釋放p結點}L=NULL;//頭指標置空cout<<"銷毀鏈表操作成功!"<<endl;}//將L重設為空白表void ClearList(LinkList &L){LinkList p;if(L!=NULL)while (L->next!=NULL)//如果鏈表非空,則置空{p=L->next;L->next=L->next->next;free(p);}L=NULL;if(L==NULL)cout<<"置空鏈表操作成功!"<<endl;}//若L為空白表,則返回TRUE,否則返回FALSEint ListEmpty(LinkList L){if (L==NULL){return 1;}elsereturn 0;}//輸出L中資料元素的個數int ListLength(LinkList L){int num=0;LinkList p;if(L!=NULL)for(p=L;p != NULL;p=p->next)num++;return num;}//用e返回L中第i個資料元素的值int GetElem(LinkList L,int i,ElemType *e){int num;LinkList p;p=L;if(L != NULL)if(i>=1 && i<=ListLength(L))for(num=0;num<i-1;num++)p=p->next;*e=p->data;cout<<"第 "<<i<<" 個資料元素的值為 "<< *e << endl;return *e;}//返回L中第1個與e滿足相等關係的資料元素的位序。void LocateElem(LinkList L,ElemType e){int position=0;LinkList p=L;if(L!=NULL)while (p!=NULL){position++;if(e==p->data)//找到滿足條件的資料cout<<"元素 "<<e<<" 鏈表中的的位置為第 "<<position<<" 位"<<endl;p=p->next;}}//若cur_e是L的資料元素,且不是第一個,則用pre_e返回它的前驅,否則操作失敗,pre_e無定義void PriorElem(LinkList L,ElemType cur_e,ElemType *pre_e){LinkList p=L;LinkList q=p;int count=0;int flag=0;//用來標識當前元素是否是首元節點if(L!=NULL)while (p->next != NULL){count++;if(cur_e==p->data){flag=1;//當前元素為首元節點break;}if(cur_e == p->next->data && cur_e != L->data){flag=0;break;}p=p->next;}if(flag==0 && count != 0 && p != NULL){cout<<cur_e<<" 的前驅結點為:"<< p->data<<endl;}if(flag==1)//首元節點沒有前驅{cout<<"第一個元素沒有前驅!!!!"<<endl;}}//若cur_e是L的資料元素,且不是最後一個,則用next_e返回它的後繼,否則操作失敗,next_e無定義void NextElem(LinkList L,ElemType cur_e,ElemType *next_e){LinkList p=L;if(L!=NULL)while (p!=NULL){if(cur_e==p->data){break;}p=p->next;}if (p!=NULL&&p->next!=NULL){*next_e=p->next->data;cout<<cur_e<<" 的後繼結點為:"<<*next_e<<endl;}elsecout<<"最後一個元素沒有後繼!!!!"<<endl;}//向已存在的無前端節點鏈表插入元素void ListInsert(LinkList &L,int i,ElemType e){LinkList p=L;LinkList q=L;LinkList s;int j=0;while (q->next!=NULL && j<i-1)//從首元節點開始尋找第i-1個節點{q=q->next;if(p->next!=q)p=p->next;//將p指向要插入節點位置的前驅節點處j++;}if(!(q->next) || j>i-1)//i小於1或者大於表長加1{cout<<"插入位置不合法!"<<endl;exit(0);}s=(LinkList)malloc(sizeof(*s));//產生新結點儲存要插入的資料結點if(!s)//分配空間失敗exit(0);s->data=e;if(i==1){s->next=p;L=s;}else{s->next=q;p->next=s;}}//頭插法建立無前端節點鏈表void ListHeadInsert(LinkList &L){LinkList p;//p指向要插入節點的位置int i,j;for(i=1,j=0;i<=10;i++,j++){p=(LinkList)malloc(sizeof(*p));if(!p)//分配空間失敗exit(0);p->data=j;if(L!=NULL)p->next=L;elsep->next=NULL;L=p;//頭指標移動}}//尾插法建立無前端節點鏈表void ListTailInsert(LinkList &L){LinkList pTail=L;//把尾賦給尾指標LinkList p;int i,j;for(i=1,j=0;i<=10;i++,j++){p=(LinkList)malloc(sizeof(*p));if(!p)//分配空間失敗exit(0);p->data=j;if(L!=NULL)pTail->next=p;//鏈表非空時,新結點插入在尾部elseL=p;//鏈表為空白時,p賦給第一個節點p->next=NULL;pTail=p;//修改尾指標指向新的尾結點}}//刪除L的第i個資料元素,並用e輸出其值void ListDelete(LinkList &L,int i,ElemType *e){LinkList p=L;LinkList q=L;int j=0;while(q->next != NULL && j < i-1)//尋找第i個結點,並令p指向其前驅{q=q->next;if(p->next!=q)p=p->next;j++;}if(!(q->next) || j > i-1){cout<<"刪除位元置不合理!"<<endl;exit(0);}if(i==1)//刪除位元置為1{q=p;*e=q->data;p=q->next;L=p;//頭指標移動}else{*e=q->data;p->next=q->next;}cout<<"刪除第 "<<i<<" 個資料 "<< *e <<" 成功"<<endl;free(q);//釋放刪除的結點}//依次對L的每個資料元素遍曆void ListTraverse(LinkList L){LinkList p=L;cout<<"輸出鏈表為:";while (p != NULL){cout<<p->data<<" ";p=p->next;}cout<<endl;}int main(){LinkList L;InitList(L);ListHeadInsert(L);//頭插法//ListTailInsert(L);//尾插法ListTraverse(L);/*int cPosition;ElemType cData;int length=ListLength(L);cout<<"請輸入需要插入位置(1-"<<length-1<<"):";cin>>cPosition;cout<<"請輸入需要插入的元素:";cin>>cData;ListInsert(L,cPosition,cData);//在特定位置插入結點ListTraverse(L);//新鏈表輸出*//*//測試ListDelete函數ElemType dNum;int dPosition;cout<<"請輸入刪除元素的位置:";cin>>dPosition;ListDelete(L,dPosition,&dNum);ListTraverse(L);*//*//測試PriorElem函數和NexElem函數ElemType cur_e,pre_e,next_e;cout<<"請輸入當前元素資料:";cin>>cur_e;PriorElem(L,cur_e,&pre_e);NextElem(L,cur_e,&next_e);*//*//測試LocateElem函數ElemType elem;cout<<"請輸入需要尋找的元素:";cin>>elem;LocateElem(L,elem);*//*//測試GetElem函數ElemType elem;int ePosition;cout<<"請輸入需要擷取元素的位置:";cin>>ePosition;GetElem(L,ePosition,&elem);*//*//測試ListLength函數int len;len=ListLength(L);cout<<"鏈表長度為:"<<len<<endl;*//*//測試ListEmpty函數int re =ListEmpty(L);cout<<re<<endl;//返回0表示非空,1表示鏈表為空白*//*//測試ClearList函數ClearList(L);*//*//測試DestroyList函數DestroyList(L);*/return 0;}