數據結構第三篇——線性表的鏈式存儲之單鏈表
阿新 • • 發佈:2017-09-04
創建 int 超出 內容 存儲結構 cat com style 找到 。
線性表的鏈式存儲結構的特點是用一組任意的存儲單元來存儲線性表的數據元素,這些單元可以分散在內存中的任意位置上,其在物理上可以是連續的,也可以是不連續的。具有鏈式存儲結構的線性表稱為線性鏈表。
為了表示出每個數據元素與其後繼之間的關系,除了存儲數據元素本身的信息之外,還需存儲指示其直接後繼的信息。這可以用一個結點(node)來完整的表示。
將節點中存儲數據元素本身信息的域稱為數據域;存儲其直接後繼位置的域稱為指針域。指針域中存儲的信息稱作指針或鏈。
一般情況下,鏈表中每個結點可以包含若幹個數據域和若幹個指針域。如果每個結點中只包含一個指針域,則稱其為單鏈表。
為了便於實現各種操作,可以在單鏈表的第一個結點之前增設一個結點,稱為頭結點,其他結點稱為表結點
帶頭結點的單鏈表描述如下:
1 typedef int Data; 2 3 struct Node 4 { 5 Data data; //數據 6 Node* next; //指針 7 }; 8 9 class LinkList 10 { 11 Node* head; //創建頭結點 12 public: 13 LinkList() //構造函數 14 { 15 head = new Node;16 head->next = NULL; 17 } 18 ~LinkList(); //析構函數 19 Data GetElem(int i); //取第i個元素的值 20 bool IsEmpty(); //判斷是否為空鏈表 21 void Create(Data* a , int n); //創建長度為n的單鏈表(頭插法) 22 void Create1(Data* a , int n); //創建長度為n的單鏈表(尾插法) 23 Node* Locate(Data e,int* i); //查找值為e的結點,返回指向e的指針 24 void Insert(Data x,int i); //將數據元素x插入到第i個位置 25 Data Delete(int i); //刪除第i個元素 26 //int _Delete(Data e); //刪除值為e的第一個元素 27 int Size(); //返回鏈表的長度 28 void Clear(); //清空 29 void Print(); //顯示元素 30 }; 31
下面則是這些操作在單鏈表上的實現:
1 //計算鏈表長度 2 int LinkList::Size() 3 { 4 Node* p; //創建指針p 5 int k; 6 p=head->next; ////p指向第一個元素結點 7 k=0; 8 while(p) 9 { 10 p=p->next; 11 ++k; 12 } 13 return k; 14 } 15 16 //顯示所有元素 17 void LinkList::Print() 18 { 19 Node* p; //創建指針p 20 p=head->next; ////p指向第一個元素結點 21 while(p) 22 { 23 cout<<p->data<<" "; 24 p=p->next; 25 } 26 cout<<endl; 27 } 28 29 //取元素 30 Data LinkList::GetElem(int i) 31 { 32 if(head->next == NULL) //為空鏈表 33 { 34 cout<<"此鏈表為空"<<endl; 35 exit(0); 36 } 37 else 38 { 39 Node* p; //創建指針p 40 int k; 41 p=head; //p指向頭結點 42 k=0; 43 while(p&&k<i) //p移到i的位置 44 { 45 p=p->next; 46 k++; 47 } 48 if(!p||k>i) //超出個數範圍 49 { 50 cout<<"第"<<i<<"個元素不存在"<<endl; 51 exit(0); 52 } 53 return (p->data); 54 } 55 } //此算法的時間復雜度為O(n) 56 57 //插入操作 58 void LinkList::Insert(Data x,int i) 59 { 60 Node* p=head; 61 int k=0; 62 while(p&&k<i-1) // 將p指到第i個位置 63 { 64 p=p->next; 65 ++k; 66 } 67 if(!p||k>i-1) //判斷是否存在第i個元素 68 { 69 cout<<"第"<<i<<"個元素不存在"<<endl; 70 exit(0); 71 } 72 Node* s = new Node; //創建此結點 73 if(!s) 74 { 75 cout<<"空間分配失敗"<<endl; 76 exit(0); 77 } 78 s->data=x; //將元素存入創建的結點 79 s->next=p->next; 80 p->next=s; 81 } 82 83 //刪除操作 84 Data LinkList::Delete(int i) 85 { 86 Node* p = head; 87 int k=0; 88 while(p&&k<i-1) //將p指到要刪除的位置 89 { 90 p=p->next; 91 ++k; 92 } 93 if(!p||p->next==NULL) //判斷刪除位置是否存在和是否有後繼 94 { 95 cout<<"刪除位置非法"<<endl; 96 exit(0); 97 } 98 Node* q = p->next; //暫存刪除結點 99 p->next = q->next; //將結點隔離出來 100 Data e=q->data; //將刪除的元素儲存起來 101 delete q; //釋放將要刪除的結點 102 return e; 103 } 104 105 bool LinkList::IsEmpty() 106 { 107 if(head->next==NULL) 108 { 109 cout<<"此鏈表為空"<<endl; 110 return true; 111 } 112 else 113 { 114 cout<<"此鏈表非空"<<endl; 115 return false; 116 } 117 } 118 119 //建立單鏈表 120 //第一種是頭插法 121 void LinkList::Create(Data* a,int n) 122 { 123 Node* p=NULL; 124 Node* q=NULL; 125 for(int i=n-1;i>=0;--i) 126 { 127 p=new Node; //創建新結點 128 p->data=a[i]; //將元素存入結點 129 p->next=head->next; //將新加入結點指向頭結點後面 130 head->next=p; //將頭結點指向新加入的結點 131 } 132 } 133 134 //第二種是尾插法 135 void LinkList::Create1(Data* a,int n) 136 { 137 Node* p=NULL; 138 Node* q=head; //創建中間結點指針 139 for(int i=0;i<n;++i) 140 { 141 p=new Node; //創建儲存元素的新結點 142 p->data=a[i]; //將元素存入創建的結點 143 p->next=q->next; //插入到終端結點之後 144 q->next=p; //終端結點指向新建結點 145 q=p; //q指向新建結點 146 } 147 p->next=NULL; 148 } 149 150 //查找給定值的結點 151 Node* LinkList::Locate(Data e,int *i) 152 { 153 *i=1; 154 Node* p=NULL; 155 p=head->next; 156 while(p) //p不為空 157 { 158 if(p->data==e) //找到元素 159 return p; 160 else 161 { 162 p=p->next; 163 ++(*i); 164 } 165 } 166 cout<<"當前鏈表中無此元素"<<endl; 167 exit(0); 168 return NULL; 169 } 170 171 //清空單鏈表 172 //保留表頭結點,把單鏈表中的 173 //其余所有結點全部釋放。 174 void LinkList::Clear() 175 { 176 Node* p=NULL; 177 Node* q=NULL; 178 p=head->next; 179 while(p) 180 { 181 q=p; 182 p=p->next; 183 delete q; 184 } 185 head->next = NULL; 186 } 187 188 //析構函數 189 //釋放單鏈表中的所有元素。 190 LinkList::~LinkList() 191 { 192 Node* p; 193 p=head; 194 while(p) 195 { 196 p=p->next; 197 delete head; 198 head=p; 199 } 200 }
需要註意的幾點:
1.在創建鏈表時有兩種創建方法,即頭插法和尾插法,具體怎麽實現請看下圖:
2.在創建終結點(即屁股結點)時要註意指向下一個結點的指針要進行處理:p->next=NULL;
3,在用完鏈表後要記得進行銷毀(釋放內存),可以在析構函數中完成。
最後則是函數的測試,放在main函數裏:
1 int main() 2 { 3 int i=0; 4 Data e; 5 int a[8]={2,4,6,8,5,1,7,9}; 6 7 LinkList list; //創建鏈表類 8 list.IsEmpty(); //判斷鏈表是否為空 9 list.Create(a,8); //將數據插入 10 list.Print(); //顯示 11 cout<<"鏈表長度:"<<list.Size()<<endl; 12 13 cout<<"輸入要插入的元素和位置:"; 14 cin>>e>>i; 15 list.Insert(e,i); //插入數據 16 list.Print(); 17 cout<<"當前鏈表長度為"<<list.Size()<<endl<<endl; 18 19 cout<<"輸入要插入的元素和位置:"; 20 cin>>e>>i; 21 list.Insert(e,i); 22 list.Print(); 23 cout<<"當前鏈表長度為"<<list.Size()<<endl<<endl; 24 25 cout<<"輸入要插入的元素和位置:"; 26 cin>>e>>i; 27 list.Insert(e,i); 28 list.Print(); 29 cout<<"當前鏈表長度為"<<list.Size()<<endl<<endl; 30 31 cout<<"輸入要查找的元素值:"; 32 cin>>e; 33 list.Locate(e,&i); //查找某元素 34 cout<<"這是第"<<i<<"個元素"<<endl<<endl; 35 36 cout<<"輸入要查找的元素值:"; 37 cin>>e; 38 list.Locate(e,&i); 39 cout<<"這是第"<<i<<"個元素"<<endl<<endl; 40 41 list.IsEmpty(); //判斷鏈表是否為空 42 43 cout<<"輸入要查找的元素位置:"; 44 cin>>i; 45 e=list.GetElem(i); //查找第i個位置的元素 46 cout<<"這個元素值為:"<<e<<endl<<endl; 47 48 cout<<"輸入要查找的元素位置:"; 49 cin>>i; 50 e=list.GetElem(i); //查找第i個位置的元素 51 cout<<"這個元素值為:"<<e<<endl<<endl; 52 53 list.IsEmpty(); //判斷鏈表是否為空 54 55 cout<<"輸入要刪除的元素位置:"; 56 cin>>i; 57 e=list.Delete(i); //刪除第i個位置的元素 58 cout<<"這個元素值為:"<<e<<endl; 59 list.Print(); 60 cout<<"當前鏈表長度為"<<list.Size()<<endl<<endl; 61 62 cout<<"輸入要刪除的元素位置:"; 63 cin>>i; 64 e=list.Delete(i); //刪除第i個位置的元素 65 cout<<"這個元素值為:"<<e<<endl; 66 list.Print(); 67 cout<<"當前鏈表長度為"<<list.Size()<<endl<<endl; 68 69 list.Clear(); 70 list.IsEmpty(); //判斷鏈表是否為空 71 72 return 0; 73 }
最後則是程序運行後的畫面了:
到這裏線性表鏈式存儲中的單鏈表就結束了,下次內容則是雙鏈表的實現。
數據結構第三篇——線性表的鏈式存儲之單鏈表