算法高频面试题4:链表操作相关的面试题

1. 链表属于比较基础的数据结构,看起来简单,实际上写起来并不简单,考察的是面试者的细心。

2. 下面以C++语言实现一个单链表,其中囊括了大部分的单链表面试题。

#include <iostream>
using namespace std;

class MyList {
	struct Node;
public:
	//1. 构造函数,让head的value永远为NULL,head作为哨兵节点
	MyList() {
		head = new Node(NULL);
		head->next = nullptr;
	}

	//2. 需要释放内存,避免内存泄漏。下面提供了两种析构链表的方法,作为对链表的思考试验
	~MyList() {
		方法一:先删除所有的head->next节点,最后删除head节点
		//if (head) {
		//	while (head->next) {
		//		Node* deleteNode = head->next;
		//		head->next = deleteNode->next;
		//		cout << "删除:" << deleteNode->data << endl;
		//		delete deleteNode;
		//	}
		//	cout << "删除:head" << endl;
		//	delete head;
		//}

		//方法二:从头结点开始删除,依次删除所有节点,也就是每次删除的都是头结点
		while (head) {
			Node* deleteNode = head;
			head = head->next;
			cout << "删除:" << deleteNode->data << endl;
			delete deleteNode;
		}
	}

	//3.在链表的尾部插入节点,从这里可以看出有一个哨兵头结点的好处,那就是不用对头结点做特殊处理
	void push_back(int value) {
		Node* tmp = head;
		//找到尾部
		while (tmp->next != nullptr) {
			tmp = tmp->next;
		}
		Node* insertNode = new Node(value);
		tmp->next = insertNode;
	}


	//4. 每次都在链表的头部插入节点,即每次在head之后进行插入
	void push_front(int value) {
		Node* insertNode = new Node(value);
		insertNode->next = head->next;
		head->next = insertNode;
	}

	//5. 在链表的指定位置插入节点,例如原链表为1,2,3,4,在第2个位置后插入6,变为1,2,6,3,4
	void insertNode(int index, int value) {
		Node* insertNode = new Node(value);
		Node* tmp = head;
		for (int i = 0; i < index; i++) {
			tmp = tmp->next;
		}
		insertNode->next = tmp->next;
		tmp->next = insertNode;
	}

	//6. 删除指定位置的节点
	void deleteNode(int index) {
		Node* tmp = head;
		Node* prev = head;
		for (int i = 0; i < index; i++) {
			prev = tmp;
			tmp = tmp->next;
		}
		prev->next = tmp->next;
		delete tmp;
	}

	//7. 删除链表中倒数第N个节点,查找倒数第N个节点同理
	void deleteNode2(int index) {
		Node* firstNode = head;
		Node* secondeNode = head;
		Node* prev = head;
		for (int i = 0; i < index; i++) {
			firstNode = firstNode->next;
		}
		while (firstNode) {
			prev = secondeNode;
			firstNode = firstNode->next;
			secondeNode = secondeNode->next;
		}
		prev->next = secondeNode->next;
		delete secondeNode;
	}

	//6. 链表的反转
	void reverseList() {
		Node* cur = head->next;
		Node* prev = nullptr;
		Node* next = cur;

		while (cur) {
			if (!cur->next) {
				head->next = cur;
			}
			next = cur->next;
			cur->next = prev;
			prev = cur;
			cur = next;
		}
	}

	//7. 链表中环的检测,以及环的入口,还需要仔细思考下,本体考察快慢指针
	bool checkCircle() {
		Node* fast = head;
		Node* slow = head;
		Node* crossPoint = nullptr;
		Node* entry = nullptr;

		while (fast->next) {
			if (fast == slow) {
				crossPoint = slow;
				fast = head;
				while (fast) {
					if (fast == slow) {
						entry = fast;
						return true;
					}
					fast = fast->next;
					slow = slow->next;
				}
			}
			fast = fast->next->next;
			slow = slow->next;
		}
		return false;
	}

	//8. 两个有序链表的合并
	void merge(MyList* list);

	//9. 求链表的中间节点,本题的解法明显是对快慢指针的考察,快节点每次走两步,
	//慢节点每次走一步,那么慢节点就是我们的中间节点,同理求数组的中间节点
	//需要注意的是,需要注意各种判断条件,链表考察的就是细心
	int midle() {
		Node* fast = head;
		Node* slow = head;		
		while (fast) {
			if (fast->next) {
				fast = fast->next->next;
			}
			else {
				break;
			}
			slow = slow->next;
		}
		return slow->data;
	}

	//10. 打印链表
	void show() {
		Node* loop = head->next;
		while (loop) {
			cout << loop->data << endl;
			loop = loop->next;
		}
	}

private:
	struct Node
	{
		int data;
		Node* next;
		Node(int val):data(val),next(nullptr){}
	};

private:
	//链表头,注意头结点的值永远为空,目的是方便链表的操作
	Node* head;
};



int main() {
	MyList* list = new MyList();
	list->push_back(10);
	list->push_back(20);
	list->push_back(30);
	list->push_back(40);
	//list->push_back(50);
	list->show();
	int mid = list->midle();
	cout << "mid:" << mid << endl;
	//list->reverseList();
	//list->insertNode(2, 25);
	//list->deleteNode(3);
	//list->deleteNode2(2);
	//list->push_front(9);
	//list->push_front(8);

	list->show();

	delete list;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值