1. 程式人生 > >單(雙向)連結串列的基本操作 C++

單(雙向)連結串列的基本操作 C++

#include"iostream"

using namespace std;

//====================單鏈表===================================

//如果不提供“頭指標”,則整個連結串列都無法訪問,連結串列的一個重要特點是插入、刪除操作靈活方便.
//插入操作處理順序:中間節點的邏輯,後節點邏輯,前節點邏輯。按照這個順序處理可以完成任何連結串列的插入操作。
//刪除操作的處理順序:前節點邏輯,後節點邏輯,中間節點邏輯。


/*單鏈表實際上是由節點(Node)組成的,一個連結串列擁有不定數量的節點。
而向外暴露的只有一個頭節點(Head),我們對連結串列的所有操作,都是通過其頭節點(head)來進行的。
節點:資料+地址*/

struct ListNode
{
	int val;
	struct ListNode *next;
	ListNode(int x) :val(x), next(NULL){}
};

//頭指標與頭結點不同,頭結點即第一個結點,頭指標是指向第一個結點的指標。連結串列中可以沒有頭結點,但不能沒有頭指標。
/*1.初始化單鏈表(無頭結點),頭指標為空*/
// void initList(Node **pNode)
// {
// 	*pNode = NULL;
// 	cout << "初始化成功!" << endl;
// }


/*2.建立單鏈表(頭插法):生成的連結串列中結點的次序和輸入的順序相反
a.先讓新節點的next指向頭節點之後
b.然後讓表頭的next指向新節點*/
void CreatListHead(ListNode *pHead,int data)
{
	ListNode *p=new ListNode(-1);
	p->val = data;
	p->next = pHead->next;
	pHead->next = p;
}

/*2.建立單鏈表(尾插法):在表的最後插入結點
a.將表尾終端結點的指標指向新結點
b.將當前的新結點定義為表尾終端結點 */
void CreatListTail(ListNode **Node, int data)
{
	if ((*Node)->next == NULL)
	{
		ListNode *p = new ListNode(-1);
		p->val = data;
		(*Node)->next = p;
		*Node = p;
		(*Node)->next = NULL;
	}
}

/*單鏈表的遍歷,並返回單鏈表長度*/
int printList(const ListNode *pHead)
{
	int len = 0;
	ListNode *p = pHead->next;
	if (p== NULL)
		cout << "連結串列為空!" << endl;
	else
	{
		while (p != NULL)
		{
			len++;
			cout << p->val << " ";
			p = p->next;
		}
		cout << endl;
	}
	return len;
}

/*刪除單鏈表:
1.宣告一節點p和q;
2.將第一個結點賦值給p;
3.迴圈:
a.將下一結點賦值給q;b.釋放p;c.將q賦值給p;
*/
bool ClearList(ListNode *pHead)
{
	ListNode *p, *q;
	p = pHead->next;
	while (p)
	{
		q = p->next;
		delete p;
		p = q;
	}
	pHead->next = NULL;
	return true;
}

/*查詢單鏈表上指定節點的資料*/
bool GetElem(ListNode *pHead, int i, int &data)
{
	ListNode *p = pHead->next;
	int j = 0;
	while (p && j < i-1)
	{
		p = p->next;
		j++;
	}
	if (!p)
		return false;
	else
	{
		data = p->val;
		return true;
	}
}

/*單鏈表指定位置插入資料:
1.找到ai-1儲存位置p
2.生成一個數據域為x的新結點*s
3.令結點*p的指標域指向新結點
4.新結點的指標域指向結點ai。*/
bool ListInsert(ListNode *pHead, int i, int data)
{
	ListNode *p = pHead;
	int j = 0;
	while (p && j < i - 1)
	{
		p = p->next;
		j++;
	}
	if (!p || j>i - 1)
		return false;
	else
	{
		ListNode *tmpPtr = new ListNode(-1);
		tmpPtr->val = data;
		tmpPtr->next = p->next;
		p->next = tmpPtr;
		return true;
	}
}

/*刪除單鏈表指定的某個結點:
1.找到ai-1的儲存位置p(因為在單鏈表中結點ai的儲存地址是在其直接前趨結點ai-1的指標域next中)
2.令p->next指向ai的直接後繼結點(即把ai從鏈上摘下)
3.釋放結點ai的空間,將其歸還給“儲存池”。*/
bool ListDelete(ListNode *pHead, int i)
{
	int j=1;
	ListNode *p, *q;
	p= pHead;
	while (p && j<i)
	{
		p = p->next;
		j++;
	}
	if (!p || j>i)
		return false;
	else
	{
		q = p->next;
		p->next = q->next;
		delete q;
		return true;
	}
}
/*單鏈表逆序:*/
bool ListReverse(ListNode *PHead)
{
	ListNode *current, *pnext, *prev;
	current = PHead->next;
	pnext = current->next;
	current->next = NULL;
	while (pnext)
	{
		prev = pnext->next;
		pnext->next = current;
		current = pnext;
		pnext = prev;
	}
	PHead->next = current;

	return true;
}

/*判斷單鏈表中是否有環:
1.使用p、q兩個指標,p總是向前走,但q每次都從頭開始走,對於每個節點,看p走的步數是否和q一樣*/
bool HasLoop(ListNode *pHead)
{
	ListNode *cur1 = pHead;
	int pos1 = 0;
	while (cur1)
	{
		ListNode *cur2 = pHead;
		int pos2 = 0;
		pos1++;
		while (cur2)
		{
			pos2++;
			if (cur1 == cur2)
			{
				if (pos1 == pos2)
					break;
				else
					return true;
			}
			cur2 = cur2->next;
		}
		cur1 = cur1->next;
	}
	return false;
}

/*獲取單鏈表倒數第N個結點值:
建立兩個指標,第一個先走n步,然後第2個指標也開始走,兩個指標步伐(前進速度)一致。當第一個結點走到連結串列末尾時,第二個節點的位置就是我們需要的倒數第n個節點的值。*/
bool GetNthNodeFromBack(ListNode *pHead, int n,int &data)
{
	int i = 1;
	ListNode *firstNode = pHead, *secNode = pHead;
	while (firstNode->next != NULL && i < n)
	{
		firstNode = firstNode->next;
		i++;
	}
	if (firstNode->next == NULL && i < n - 1)
	{
		cout << "n超出連結串列長度" << endl;
		return false;
	}
	while (firstNode->next != NULL)
	{
		secNode = secNode->next;
		firstNode = firstNode->next;
	}
	data = secNode->val;
	return true;
}


//=====================================================



//====================雙向迴圈連結串列=======================
/*雙向迴圈連結串列的結構:資料、next指標、prior指標
1.連結串列由頭指標head惟一確定的。
2.帶頭結點的雙鏈表的某些運算變得方便。
3.將頭結點和尾結點連結起來,為雙(向)迴圈連結串列。*/
struct NodeType2
{
	int val;
	NodeType2 *next, *prior;
	NodeType2(int x) :val(x), next(NULL), prior(NULL) {};
};

//建立雙向連結串列
void CreateListtype2(NodeType2 **Node, int data)
{
	NodeType2 *tmpPtr = (*Node)->next;
	NodeType2 *p = new NodeType2(data);
	(*Node)->next = p;
	p->prior = *Node;
	p->next = tmpPtr;

	*Node = p;
}

/*雙鏈表的前插操作*/
bool ListType2Insert1(NodeType2 *pHead, int i, int data)
{
	int j = 0;
	NodeType2 *p = pHead;
	while (p && j<i)
	{
		p = p->next;
		j++;
	}
	if (!p && j < i - 1)
		return false;
	else
	{
		NodeType2 *tmpTpr = new NodeType2(data);
		tmpTpr->next = p;
		tmpTpr->prior = p->prior;
		p->prior->next = tmpTpr;
		p->prior = tmpTpr;
		return true;
	}


}

/*雙鏈表的後插操作*/
bool ListType2Insert2(NodeType2 *pHead, int i, int data)
{
	int j = 0;
	NodeType2 *p = pHead;
	while (p && j<i)
	{
		p = p->next;
		j++;
	}
	if (!p && j < i - 1)
	{
		cout << "超出連結串列長度!" << endl;
		return false;
	}
	else
	{
		NodeType2 *tmpPtr = new NodeType2(data);
		tmpPtr->next = p->next;
		p->next->prior = tmpPtr;
		p->next = tmpPtr;
		tmpPtr->prior = p;
		return true;
	}
}

/*雙鏈表上刪除結點*p*/
bool ListType2Delete(NodeType2 *pHead, int i)
{
	int j = 0;
	NodeType2 *p = pHead;
	while (p && j<i)
	{
		p = p->next;
		j++;
	}
	if (p && j < i - 1)
	{
		cout << "超出連結串列長度!" << endl;
		return false;
	}
	else
	{
		p->prior->next = p->next;
		p->next->prior = p->prior;
		delete p;
		return true;
	}
}

//=============================================


int main()
{
	//=========單鏈表==============
	//ListNode *L = new ListNode(-1);
	//int n;
	//ListNode* tmpPtr = L;
	//while (cin >> n)//ctrl+z結束
	//{
	//	//CreatListHead(L, n);
	//	CreatListTail(&tmpPtr, n);//為什麼傳指標不行 非得指標的指標
	//}
	//int len = printList(L);
	//int data = 0;
	// bool isGetElem = GetElem(L, 2, data);
	// bool isInsertElem = ListInsert(L, 2, 4);
	// bool isClear = ClearList(L);
	//bool isDelete = ListDelete(L, 1);
	//bool isReverse = ListReverse(L);

	//tmpPtr->next = L;
	//bool isloop=HasLoop(L);

	//bool IsGet = GetNthNodeFromBack(L, 2, data);
	//len = printList(L);


	//============雙鏈表==================
	NodeType2 *L = new NodeType2(-1);
	int n = 0;
	NodeType2 *tmpPtr = L;
	while (cin >> n)
	{
		CreateListtype2(&tmpPtr, n);
	}

	bool isInsert = ListType2Insert2(L, 2, 4);
	bool isDelete = ListType2Delete(L, 3);

	system("pause");
	return 0;
}