LinkedList单向链表的C++实现

1_Linked List

Singly linked lists are a type of a linked list where each node points to the next node in the sequence. It does not have any pointer that points to the previous node. That means we can traverse the list only in forward direction.

image-20210722155355425

1.0_list.h

头文件中包含节点结构体类型的定义和单向链表类的定义。

#ifndef LIST_H
#define LIST_H
struct Node {
	int data;
	Node *next;
};
typedef Node* NodePtr;
class CLinkedList {
private:
	NodePtr head;
public:
	CLinkedList();
	void insertAtFront(int value);
	void insertAtBack(int value);
	void insertAfter(int key, int value);
	int topFront();
	int topBack();
	int popFront();
	int popBack();
	void remove(int key);
	void print();
	bool isEmpty();
	bool find(int key);
	void reverse();
	bool hasCycle();
	void mergeTwoLists();
	void removeNthFromEnd(int N);
	NodePtr middleNode();
	//206,141,21,19,876 in Leetcode
};
#endif

1.1_CLinkedList

构造函数:用于创建一个新的链表,其中无内容,头节点指向空指针。

CLinkedList::CLinkedList() {
	head = nullptr;
}

1.2_insertAtFront

在链表的最前面插入节点。该过程可以分为三个步骤。

  • 创建新的节点,将数据存入该节点的数据区;

  • 新的节点的next指针指向原来的头节点;

  • 将新的节点作为原来的头节点。

时间复杂度和空间复杂度均为O(1)

//Insert value at the front of the list
void CLinkedList::insertAtFront(int value) {
	NodePtr node = new Node;
	node->data = value;
	node->next = nullptr;
	if (isEmpty()) {
		head = node;
	}
	else {
		node->next = head;
		head = node;
	}
}

1.3_insertAtBack

在链表的末尾插入节点。该过程可以分为三个步骤。

  • 创建新的节点,将数据存入该节点的数据区。

  • 创建一个节点用于循环,让该节点走到链表末端。

  • 让该节点的next指针指向新创建的节点。

时间复杂度为O(n),空间复杂度为O(1)

//Insert value at the back of the list
void CLinkedList::insertAtBack(int value) {
	NodePtr node = new Node;
	node->data = value;
	node->next = nullptr;
	if (isEmpty()) {
		head = node;
	}
	else {
		NodePtr currPtr = head;
		while (currPtr->next != nullptr) {
			currPtr = currPtr->next;
		}
		currPtr->next = node;
	}
}

1.4_insertAfter

在链表第一次出现key数据之后插入节点。该过程分为三个步骤。

  • 创建新的节点,将数据存入该节点的数据区。

  • 创建一个节点用于循环,直到该节点找到key或者走到末端。

    • 如果走到末端,进行异常处理。函数结束。
    • 如果找到key,则进入下一步。
  • 新创建的节点插入key节点

    • 如果key在末尾节点,则按照1.3末尾插入的方式进行插入节点
    • 如果key在其他节点:
      • 新的节点的next指针指向当前节点的下一个节点。
      • 当前节点的next指针指向新的节点。

时间复杂度为O(n),空间复杂度为O(1)

//Insert value at the after key
void CLinkedList::insertAfter(int key, int value) {
	NodePtr node = new Node;
	node->data = value;
	node->next = nullptr;
	NodePtr currPtr = head;
	while (currPtr != nullptr && currPtr->data != key) {
		currPtr = currPtr->next;
	}
	if (currPtr == nullptr) {
		cout << "warning:InsertAfter,key:" << key << " " << "NOT find!" << endl;
	}
	else if (currPtr->next == nullptr) {
		currPtr->next = node;
	}
	else {
		node->next = currPtr->next;
		currPtr->next = node;
	}
}

1.5_topFront

返回链表的链头数据。

  • 如果链表为空,进行异常处理,返回-1。
  • 如果链表不为空,则返回头节点的数据区。

时间复杂度和空间复杂度均为O(1)

//Return the data at first node
int CLinkedList::topFront() {
	if (isEmpty()) {
		cout << "warning:TopFront,list IS empty!" << endl;
	}
	else {
		return head->data;
	}
	return -1;
}

1.6_topBack

返回链表的链尾元素。

  • 如果链表为空,进行异常处理,返回-1;
  • 如果链表不为空
    • 创建节点用于循环,直到节点的next指针指向NULL
    • 返回该节点的数据区。

时间复杂度为O(n),空间复杂度为O(1)

//Return the data at last node
int CLinkedList::topBack() {
	if (isEmpty()) {
		cout << "warning:TopBack,list IS empty!" << endl;
	}
	else {
		NodePtr currPtr = head;
		while (currPtr->next != nullptr) {
			currPtr = currPtr->next;
		}
		return currPtr->data;
	}
	return -1;
}

1.7_popFront

返回并删除链表的第一个节点。

  • 如果链表为空,异常处理。
  • 如果链表不为空
    • 保存原头节点数据,创建新的节点指向头节点的下一个节点。
    • 删除原头节点。
    • 将创建的新的节点作为头节点。

时间和空间复杂度均为O(1)

//Removes the item at front of the linked list and return 
int CLinkedList::popFront() {
	int temp;
	if (isEmpty()) {
		cout << "warning:PopFront,list IS empty!" << endl;
	}
	else {
		NodePtr nextPtr = head->next;
		temp = head->data;
		delete head;
		head = nextPtr;
		return temp;
	}
	return -1;
}

1.8_popBack

返回并删除链表的末尾节点。

  • 如果链表为空,则进行异常处理。
  • 如果链表不为空
    • 创建节点用于循环,直到该节点的next指针指向NULL,同时保存其上一个节点。
    • 保存当前节点的数据,删除当前节点。
    • 将上一个节点的next指针指向NULL。

时间复杂度为O(n),空间复杂度为O(1)

//Remove the item at the end of the linked list and returnint CLinkedList::popBack() {	int temp;	if (isEmpty()) {		cout << "warning:PopBack,list IS empty!" << endl;	}	else if (head->next == nullptr) {		temp = head->data;		delete head;		head = nullptr;		return temp;	}	else {		NodePtr currPtr = head;		NodePtr prevptr = nullptr;		while (currPtr->next != nullptr) {			prevptr = currPtr;			currPtr = currPtr->next;		}		temp = currPtr->data;		delete currPtr;		prevptr->next = nullptr;		return temp;	}	return -1;}

1.9_remove

删除链表中第一个数据为key的节点。

  • 如果链表为空链表,进行异常处理。
  • 创建节点用于循环,直到该节点的数据为key或者走到链表尾,并记录上一个节点。
    • 走到链表尾,则进行异常处理。
    • 判断key的位置。
      • 如果key为head的数据,则按照删除第一个节点处理。
      • 如果key为末尾节点的数据,则按照删除末尾节点的处理。
      • 上一个节点的next指针指向当前节点的下一个节点,删除当前节点。

时间复杂度为O(n),空间复杂度为O(1)

//Removes a node with value 'key'void CLinkedList::remove(int key) {	if (isEmpty()) {		cout << "warning:Remove,list IS empty!" << endl;		return; }	NodePtr currPtr = head;	NodePtr prevPtr = nullptr;	while (currPtr != nullptr && currPtr->data != key) {		prevPtr = currPtr;		currPtr = currPtr->next;	}		if (currPtr == nullptr) {		//key is not find;		cout << "warning:Remove,key:"<<key<<" "<<"NOT find!" << endl;		return;	}	else if (prevPtr == nullptr) {		//it is the first item		head = currPtr->next;		delete currPtr;		return;	}	else if (currPtr->next == nullptr) {		//it is the last item		prevPtr->next = nullptr;		delete currPtr;		currPtr == nullptr;		return;	}	else {		prevPtr->next = currPtr->next;		delete currPtr;		currPtr = nullptr;		return;	}}

1.10_print

打印链表。

循环打印链表中的元素,直到当前指针为NULL

时间复杂度为O(n),空间复杂度为O(1)

//Print the linked listvoid CLinkedList::print() {	NodePtr currPtr = head;	while (currPtr != nullptr) {		cout << currPtr->data << "	";		currPtr = currPtr->next;	}	cout << endl;}

1.11_isEmpty

判断链表是否为空链表。

判断链表的头指针是否为空指针即可。

时间复杂度和空间复杂度均为O(1)

//Check if a linked list is emptybool CLinkedList::isEmpty() {	return head == nullptr;}

1.12_find

判断链表中是否存在数据为key的节点。

  • 如果链表为空,则不存在。
  • 创建节点用于循环
    • 如果在过程中找到,则返回存在。
    • 如果直到尾节点都没有找到,则返回不存在。

时间复杂度为O(n),空间复杂度为O(1)

//Check if a key is in the listbool CLinkedList::find(int key) {	if (isEmpty()) {		return false;	}	else {		NodePtr currPtr = head;		while (currPtr != nullptr) {			if (currPtr->data == key) {				return true;			}			currPtr = currPtr->next;		}	}	return false;}

1.14_reverse

对链表进行一个反转。使用迭代的方法。

  • 空链表,则直接返回。
  • 创建循环节点和其前一个节点直到链表末尾。
    • 当前节点指向上一个节点。
    • 上一个节点移动到当前节点。
    • 当前节点移动到下一个节点。

时间复杂度O(n),空间复杂度O(1)

image-20210722173137622

//Reverse the Linked listvoid CLinkedList::reverse() { 	if (isEmpty()) { return; }	//迭代	NodePtr currPtr = head;	NodePtr prevPtr = nullptr;	while (currPtr != nullptr) {		NodePtr nextPtr = currPtr->next;		currPtr->next = prevPtr;		prevPtr = currPtr;		currPtr = nextPtr;	}	delete currPtr;	head = prevPtr;	return; }

1.13_hasCycle

判断链表是否有环。

Floyd判圈法。

如果存在圈,走得快的和走得慢的人总会相遇。

时间复杂度O(n),空间复杂度O(1)

//Check if a list has cyclebool CLinkedList::hasCycle() { 	NodePtr slow = head;	NodePtr fast = head;	while (fast != nullptr && fast->next != nullptr) {		slow = slow->next;		fast = fast->next->next;		if (slow == fast) {			return true;		}	}	return false;}

1.15_mergeTwoLists

连接两个有序链表。

还没写


1.16_removeNthFromEnd

移除倒数第N个节点。

  • 判断N是否异常。
  • 快指针先走,满指针到快指针走了N-1步开始走。
  • 快指针再走一步,快慢指针同时走。
  • 快指针走到终点,满指针走到需要删除的前一个节点。

永远也追不上比我们先出发的人。

时间复杂度O(n),空间复杂度O(1)

//Remove the Nth element from the endvoid CLinkedList::removeNthFromEnd(int N) { 	//如果N<=0,不符合条件	if (N <= 0) {		cout << "warning:RemoveNthFromEnd,N:" << N << " " << "Must>=0!" << endl;		return;	}	//如果为空,则没有东西可以删除	if (isEmpty()) {		cout << "warning:RemoveNthFromEnd,the list IS empty"<< endl;		return;	}	NodePtr slow = head;	NodePtr fast = head;	//	for (int i = 1; i < N; i++) {		fast = fast->next;		if (fast == nullptr) {			cout << "warning:RemoveNthFromEnd,N:" << N << " " << "is over!" << endl;			return;		}	}	fast = fast->next;	if (fast == nullptr) {		NodePtr nextPtr = head->next;		delete head;		head = nextPtr;		return;	}	while (fast->next != nullptr) {		fast = fast->next;		slow = slow->next;	}	NodePtr nextPtr = slow->next;	slow->next = nextPtr->next;	nextPtr->next = nullptr;	delete nextPtr;	return; }

1.17_middleNode

返回中间节点。

还没写

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值