數據結構學習筆記 (二)

線性表的鏈式表示和實現

單鏈表

鏈式結構的特點是用一組任意的存儲元素來存儲線性表的元素,在內存中可以是連續的也可以是不連續的。對於單鏈表來說,存儲數據元素除了本身信息外(數據域),還要存儲指示其直接後續的信息(指針域)。

struct Node
{
	int data;
	Node *next;
};
class LinkList
{
	Node *head;

public:
	LinkList(){ head = new Node; head->next = NULL; };
	~LinkList(){ delete head; };
	void Create(int n);			//創建長度爲n的單鏈表
	int GetElem(int i);			//獲取第i個元素
	int Locate(int e);			//返回第一個與e匹配的元素位序
	bool IsEmpty(){ return (head->next == NULL); }//判斷是否爲空表
	int Prior(int e);			//e的前驅
	int Next(int e);			//e的後續
	void Insert(int x, int i);	//將x插入到i位置
	int Delete(int i);			//刪除表中第i個元素
	void Clear();				//清空
	void Print();				//輸出
};

結構體Node用來表示鏈表的每一個元素分別是數據域和它的指針域;

取元素

int LinkList::GetElem(int i){
	Node *p;
	int k, j;
	if (head->next == NULL)
	{
		cout << "表爲空" << endl;
		exit(0);
	}
	else
	{
		p = head;
		k = 0;
		while (p && k<i)
		{
			p = p->next;
			k++;
		}
		if (!p||k>i)
		{
			cout << "第" << i << "個元素不存在" << endl;
			exit(0);

		}
		return(p->data);
	}
}

時間複雜度O(n);


插入操作

void LinkList::Insert(int x, int i){
	Node *p = head;
	int k = 0;
	while (p && k<i-1)
	{
		p = p->next;
		k++;
	}
	if (!p||k>i-1)
	{
		cout << "第" << i - 1 << "個元素不存在" << endl;
		exit(0);
	}
	Node *s = new Node;
	if (!s)
	{
		cout << "空間分配失敗" << endl;
		exit(0);
	}
	s->data = x;
	s->next = p->next;
	p->next = s;

}

插入操作需要從鏈表的第一個節點開始根據後續的指針找到插入位置的前一個節點,然後把這個節點的後續指針指向新插入的節點,新插入的節點的後續指針則指向之前這個位置的節點。

刪除操作

int LinkList::Delete(int i){
	Node *p = head;
	int k = 0;
	while (p&&k<i-1)
	{
		p = p->next;
		k++;
	}
	if (!p||p->next==NULL)
	{
		cout << "刪除位置非法" << endl;
		exit(0);
	}
	Node *q = p->next;		//暫存刪除節點
	p->next = q->next;		//刪除
	int e = q->data;
	delete q;
	return e;

}

刪除操作也需要從第一個節點開始直到找到第i-1個節點,然後把i-1位置節點的後續指向i+1位置的節點,然後把第i位置的節點在內存中清除才能完成刪除操作。

建立單鏈表

void LinkList::Create(int n){
	Node *p;
	for (int i = 0; i < n; i++)
	{
		p = new Node;
		cin >> p->data;
		p->next = head->next;
		head->next == p;
	}
}

雙向鏈表

雙向鏈表與單鏈表相比,最大的不同就是雙向鏈表的元素不僅有數據和後續指針,它還有前驅的指針。通過一個節點不僅可以向前查找,也可以向後查找。

struct DNode
{
	int data;
	DNode *prior;		//前驅指針
	DNode *next;		//後續指針
};
class DBList
{
	DNode *head;

public:
	DBList(){ head = new DNode; head->next = NULL; head->prior == NULL; };
	~DBList();
	void Create(int n);		//創建長度爲n的雙鏈表
	int GetElem(int i);		//取表中第i個元素
	DNode Locate(int e);	//返回第一個與e匹配的節點指針
	bool IsEmpty();
	void Insert(int x, int i);
	int Delete(int i);
	void Clear();
};

在雙鏈表中,有些操作如取元素,求表長,定位等,只涉及一個方向的指針,則這些操作的算法描述和單鏈表相同。但在進行插入,刪除操作時有很大的不同,在雙鏈表中需同時修改兩個方向上的指針,還要小心修改順序。

雙鏈表的節點刪除操作

p -> prior -> next = p -> next;
if(!p->next)
p -> next -> prior = p -> prior;

雙鏈表的節點插入操作

s = new DNode;
s -> data = e;
s -> prior = p -> prior;
p -> prior = next = s;
p -> prior = s;
s -> next = p;

循環鏈表

循環鏈表是線性鏈表的一種變形,一般的鏈表結構最後一個節點的指針域爲空,表示鏈表的結束。若使最後一個節點的指針指向頭節點,則鏈表呈環狀,稱循環鏈表。


小結

鏈式存儲結構特點:

優點:
1.節點空間的動態申請和動態釋放,克服了順序存儲結構中需要預先設定數據元素的最大個數的缺點。
2.數據元素之間的次序是用指針來控制的,不像在順序存儲結構中進行插入,刪除時需要移動大量數據元素。

缺點:
1.每個節點的指針域需要額外的存儲空間,特別是當每個節點的數據域所佔空間不是很大時,指針域所佔空間就會顯得很大。
2.鏈式存儲結構是一種非隨機存儲結構,不能直接訪問,從而增加了算法的時間複雜度。



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