在此之前,我整理了用順序表存儲線性表的方法,但是順序表具有以下缺點:
- 列表內容插入和刪除非常費勁。需要移動大量元素。
- 表的容量難以確定。因爲順序表中數組的長度需要事先確定,所以難以確定合適的規模。
- 造成存儲空間的“碎片”。數組要求連續的存儲空間,若不連續則不能使用,造成存儲空間的“碎片”現象。
這一次,我們嘗試用單鏈表存儲線性表。
有空的話,可以嘗試用循環鏈表和雙鏈表來改善,是個很高級的東西。
一、 單鏈表的存儲方法
通過每個指針的指針域連接線性表的數據元素。
二、單鏈表的實現
利用結構體類型來描述單鏈表的結點
template<class T>
struct Node
{
T data; //指針域
Node<T> * next; //數據域
};
將線性表的抽象數據類型定義在單鏈表存儲結構下用C++中的class實現。
template<class T>
class LinkList
{
public:
LinkList();
LinkList(T a[], int n);
~LinkList();
int Length(); //求單鏈表的長度
T Get(int i); //按位查找,查找第i個結點的元素值
int Locate(T x); //按值查找,查找元素值爲x的結點的位置
void Insert(int i, T x); //在第i個位置插入元素值爲x的結點
T Delete(int i); //刪除第i個結點
void PrintList(); //遍歷
private:
Node<T> * first; //單鏈表的頭指針
};
1.構造函數
①無參構造函數
template<class T>
LinkList<T>::LinkList()
{
first = new Node<T>;
first->next = NULL;
}
②有參構造函數
template<class T>
LinkList<T>::LinkList(T a[], int n)
{
first = new Node<T>;
first->next = NULL;
/*
1.頭插法建立單鏈表
for(int i = 0; i < n; i++)
{
Node<T> * s = new Node<T>;
s->data = a[i];
s->next = first->next; //將節點s插到頭節點之後
first->next = s;
}
*/
// 2.尾插法建立單鏈表
Node<T> * r = first; //尾指針初始化
for(int i = 0; i < n; i++)
{
Node<T> * s = new Node<T>;
s->data = a[i];
r->next = s;
r = s;
}
r->next = NULL;
}
2.按位查找算法 Get
template<class T>
T LinkList<T>::Get(int i)
{
//工作指針p和累加器count初始化
Node<T> * p = first->next;
int count = 1;
while(p != NULL && count < i)
{
p = p->next;
count++;
}
if(p == NULL)
throw "位置異常";
else
return p->data;
}
3.按值查找算法 Locate
template<class T>
int LinkList<T>::Locate(T x)
{
Node<T> * p = first->next;
int count = 1; //用來記錄光標的位置
while(p != NULL)
{
if(p->data == x)
return count;
p = p->next;
}
return 0; //退出循環表示查找失敗
}
4.插入算法
void LinkList<T>::Insert(int i, T x) //在第i個位置插入元素x
{
Node<T> * p = first;
int count = 0;
//找出第i-1個元素
while(p != NULL && count < i - 1)
{
p = p->next; //工作指針p向後移
count++;
}
if(p == NULL)
throw "位置異常";
else
{
Node<T> * s = new Node<T>;
s->data = x;
s->next = p->next;
p->next = s;
}
}
5.刪除算法
template<class T>
T LinkList<T>::Delete(int i)
{
Node<T> * p = first;
int count = 0;
while(p != NULL && count < i - 1)
{
p = p->next;
count++;
}
if(p == NULL)
throw "位置異常";
else
{
//暫存被刪節點
Node<T> * q = p->next;
int x = q->data;
p->next = q->next;
delete q;
return x;
}
}
7.求鏈表的長度
int LinkList<T>::Length()
{
//工作指針p和累加器count初始化
Node<T> * p = first->next;
int count = 0;
while(p != NULL)
{
count++;
p = p->next;
}
return count;
}
8.遍歷
void LinkList<T>::PrintList()
{
Node<T> * p = first->next;
while(p != NULL)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
9.析構函數算法
template<class T>
LinkList<T>::~LinkList()
{
Node<T> *q = new Node<T>;
while(first != NULL) //釋放單鏈表的每個結點的存儲空間
{
q = first; //暫存被釋放結點
first = first->next; //first指向被釋放結點的下一個結點
delete q;
}
}
完整代碼如下:
#include <iostream>
#define maxSize 100
using namespace std;
template<class T>
struct Node
{
T data; //指針域
Node<T> * next; //數據域
};
template<class T>
class LinkList
{
public:
LinkList();
LinkList(T a[], int n);
~LinkList();
int Length(); //求單鏈表的長度
T Get(int i); //按位查找,查找第i個結點的元素值
int Locate(T x); //按值查找,查找元素值爲x的結點的位置
void Insert(int i, T x); //在第i個位置插入元素值爲x的結點
T Delete(int i); //刪除第i個結點
void PrintList(); //遍歷
private:
Node<T> * first; //單鏈表的頭指針
};
template<class T>
LinkList<T>::LinkList()
{
first = new Node<T>;
first->next = NULL;
}
template<class T>
LinkList<T>::LinkList(T a[], int n)
{
first = new Node<T>;
first->next = NULL;
/*
1.頭插法建立單鏈表
for(int i = 0; i < n; i++)
{
Node<T> * s = new Node<T>;
s->data = a[i];
s->next = first->next; //將節點s插到頭節點之後
first->next = s;
}
*/
// 2.尾插法建立單鏈表
Node<T> * r = first; //尾指針初始化
for(int i = 0; i < n; i++)
{
Node<T> * s = new Node<T>;
s->data = a[i];
r->next = s;
r = s;
}
r->next = NULL;
}
template<class T>
void LinkList<T>::PrintList()
{
Node<T> * p = first->next;
while(p != NULL)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
template<class T>
int LinkList<T>::Length()
{
//工作指針p和累加器count初始化
Node<T> * p = first->next;
int count = 0;
while(p != NULL)
{
count++;
p = p->next;
}
return count;
}
template<class T>
T LinkList<T>::Get(int i)
{
//工作指針p和累加器count初始化
Node<T> * p = first->next;
int count = 1;
while(p != NULL && count < i)
{
p = p->next;
count++;
}
if(p == NULL)
throw "位置異常";
else
return p->data;
}
template<class T>
int LinkList<T>::Locate(T x)
{
Node<T> * p = first->next;
int count = 1; //用來記錄光標的位置
while(p != NULL)
{
if(p->data == x)
return count;
p = p->next;
}
return 0; //退出循環表示查找失敗
}
template<class T>
void LinkList<T>::Insert(int i, T x) //在第i個位置插入元素x
{
Node<T> * p = first;
int count = 0;
//找出第i-1個元素
while(p != NULL && count < i - 1)
{
p = p->next; //工作指針p向後移
count++;
}
if(p == NULL)
throw "位置異常";
else
{
Node<T> * s = new Node<T>;
s->data = x;
s->next = p->next;
p->next = s;
}
}
template<class T>
T LinkList<T>::Delete(int i)
{
Node<T> * p = first;
int count = 0;
while(p != NULL && count < i - 1)
{
p = p->next;
count++;
}
if(p == NULL)
throw "位置異常";
else
{
//暫存被刪節點
Node<T> * q = p->next;
int x = q->data;
p->next = q->next;
delete q;
return x;
}
}
template<class T>
LinkList<T>::~LinkList()
{
Node<T> *q = new Node<T>;
while(first != NULL) //釋放單鏈表的每個結點的存儲空間
{
q = first; //暫存被釋放結點
first = first->next; //first指向被釋放結點的下一個結點
delete q;
}
}
int main()
{
int a[maxSize], i, SearchPos, NewPos, NewItem, DelPos ;
int n = 0;
//創建順序表
cout << "請輸入順序表長度:" ;
cin >> n ; //輸入樣本數目(表長)
cout << "請輸入表中所有元素:";
for (i = 0 ; i < n; i++)
{
cin >> a[i] ;
}
LinkList<int> linkList(a, n);
cout << "該順序表爲:";
linkList.PrintList(); //顯示順序表
cout << "請輸入所查找的元素的位置:" ;
cin >> SearchPos ; //輸入查找位置
cout << "該位置的元素爲:" << linkList.Get(SearchPos) << endl ; //輸出查找的數據元素值
cout << "請輸入所插入元素的值:" ;
cin >> NewItem ; //插入位置輸入
cout << "請輸入所插入的元素的位置:" ;
cin >> NewPos ; //插入元素輸入
linkList.Insert(NewPos, NewItem) ; //新數據插入順序表中
cout << "插入後的順序表爲:" ;
linkList.PrintList(); //插入數據後,輸出新的順序表
cout << "請輸入所刪除元素的位置:" ;
cin >> DelPos ; //輸入刪除元素位置
linkList.Delete(DelPos) ; //按位置刪除數據
cout << "刪除後的順序表爲:" ;
linkList.PrintList();
return 0 ;
}