C++資料結構-單鏈表建立
阿新 • • 發佈:2019-02-08
前邊我們建立了順序儲存結構的線性表,簡稱順序表,順序表最大的問題是:插入和刪除需要移動大量的元素。為了解決 這個問題, 我們引入鏈式儲存結構的線性表,簡稱連結串列,連結串列與順序表不同,連結串列的每個結點在記憶體中是分開存放的,每個結點都包含資料域和指標域:
- 資料域 :儲存資料元素本身
- 指標域 :儲存相鄰結點的地址
鏈式儲存結構的線性表有
- 單鏈表:每個結點只包含直接後繼的地址資訊
- 迴圈連結串列: 單鏈表中的最後一個結點的直接後繼為第一個結點
- 雙向連結串列: 單鏈表中的結點包含直接前驅和後繼的地址資訊
- 雙向迴圈連結串列 :雙向連結串列的最後一個結點的後繼為第一個結點,第一個結點的前驅為最後一個結點
連結串列中的基本概念
- 頭結點 : 連結串列中的輔助結點,包含指向第一個資料元素的指標
- 資料結點:連結串列中代表資料元素的結點,包含資料元素與地址兩部分
- 尾結點:連結串列中的最後一個數據結點,包含的地址資訊為空
這裡我們建立的單鏈表,結點可以 定義為如下
struct Node : public MyObject
{
T value; //資料域
Node* Next; //指標域
};
單鏈表的內部結構如下,頭結點不儲存實際的資料元素 ,只是為了資料元素定位,方便插入和刪除操作
下邊我們直接來看程式碼中的實現
#ifndef __LINKLIST_H__ #define __LINKLIST_H__ #include "List.h" namespace MyLib { template <typename T> class LinkList : public List<T> { private: struct Node : public MyObject { T value; //資料域 Node* Next; //指標域 }; mutable struct : public MyObject { char reserved[sizeof(T)]; //作為佔位用,不存放資料 Node* Next; }m_header; int m_length; //儲存連結串列長度 Node* m_current; //指向當前的結點 int m_step; // Node* position(int index) const //獲取index處的結點 { Node* ret = reinterpret_cast<Node*>(&m_header); for (int i=0; i<index; i++) { ret = ret->Next; } return ret; } virtual Node* create() { return new Node; } virtual void destroy(Node* p) { delete p; } public: LinkList() { m_length = 0; m_header.Next = NULL; m_current = NULL; m_step = 1; } bool insert( const T& e) //尾部插入結點 { return insert(m_length, e); } bool insert(int index, const T& e) //插入結點 { bool ret = ( (0 <= index)&&(index <= m_length) ); if (ret) { Node* currentNode = position(index); Node* newNode = create(); newNode->value = e; newNode->Next = currentNode->Next; currentNode->Next = newNode; m_length++; } else { THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Bounds Exception..."); } return ret; } bool remove(int index) //刪除結點 { bool ret = ( (0 <= index)&&(index < m_length) ); if (ret) { Node* currentNode = position(index); Node* toRemove = currentNode->Next; if (m_current == toDel) { m_current = toDel->Next; } currentNode->Next = toRemove->Next; m_length--; destroy(toRemove); } else { THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Bounds Exception..."); } return ret; } bool get(int index, T& e) //獲取具體位置的結點元素 { bool ret = ( (0 <= index)&&(index < m_length) ); if (ret) { Node* currentNode = position(index); e = currentNode->Next->value; } else { THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Bounds Exception..."); } return ret; } bool set(int index, const T& e)const //設定具體位置的結點元素 { bool ret = ( (0 <= index)&&(index < m_length) ); if (ret) { Node* currentNode = position(index); currentNode->Next->value = e; } else { THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Bounds Exception..."); } return ret; } int find(const T& e) const //連結串列中尋找元素位置 { Node* tofind = m_header.Next; for (int i=0; i<m_length; i++) { if (e == tofind->value) { return i; } else { tofind = tofind->Next; } } return -1; } void move(int index, int step = 1) //遊標移動初始化 { bool ret = ( (0<=index)&&(index < m_length) ); if (ret) { m_current = position(index)->Next; m_step = step; } else { THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Exception..."); } } void next() //遊標移動到下一個位置 { int i=0; while ( (!end())&&(i<m_step) ) { m_current = m_current->Next; i++; } } bool end() //判斷遊標是否到達連結串列最尾處 { return m_current == NULL; } T current() //返回遊標所指處的元素 { if (!end()) { return m_current->value; } else { THROW_EXCEPTION(IndexOutOfBoundsException, "Index Out Of Exception..."); } } int length()const //返回列表長度 { return m_length; } void clear() //清空列表 { while(m_header.Next) { remove(m_length-1); } } }; } #endif //__LINKLIST_H__
上邊我們就基本把單鏈表的內容實現完了,下邊我們來在main函式中使用一下
#include <iostream>
#include <string>
#include "LinkList.h"
using namespace std;
using namespace MyLib;
int main()
{
LinkList<int> list;
for (int i=0; i<10; i++)
{
list.insert(i);
}
list.set(2, 23);
for (list.move(0); !list.end(); list.next()) //採用遊標方式遍歷連結串列
{
cout << list.current() << endl;
}
cout << "find(3) = " << list.find(3) << endl;
system("pause");
return 0;
}
編譯執行
總結
- 連結串列中的資料元素在實體記憶體中無相鄰關係
- 連結串列中的結點都包含資料域與指標域
- 頭結點用於輔助資料元素的定位,方便插入和刪除操作
- 插入和刪除操作需要保證連結串列的完整性