注意头结点的处理,如果倒叙记得将新的尾节点指向空。
示例一
给定一个整数num,如何在节点值有序的链表中插入一个节点值为num的节点,并且保证这个单链表依然有序。
#include<iostream>
#include<thread>
using std::endl;
using std::cout;
template<typename T> struct Node{
T data;
Node<T> *next;
};
template<typename T> class listStruct {
public:
listStruct() = default;
listStruct(Node<T> *h) : head(h) {}
~listStruct() {
Node<T> *temNext;
while (head){
temNext = head;
head = head->next;
delete temNext;
}
}
void buildList(const int *sortArray, const int &length);
void displayList();
void addNode(const int &data);
private:
Node<T> *head;
};
template<typename T> void listStruct<T>::addNode(const int &data) {
Node<T> *newNode = new Node<T>;
newNode->data = data;
newNode->next = NULL;
if (head == NULL) {
head = newNode;
}
if (head->data > data) {
newNode->next = head;
head = newNode;
return;
}
Node<T> *tem = head;
Node<T> *last = NULL;
while (tem) {
if (tem->data > data){
newNode->next = tem;
last->next = newNode;
return;
}
last = tem;
tem = tem->next;
}
last->next = newNode;
}
template<typename T> void listStruct<T>::displayList() {
Node<T> *tem = head;
cout << "start:" << endl;
while (tem){
cout << tem->data << endl;
tem = tem->next;
}
cout << "end!" << endl;
}
template<typename T> void listStruct<T>::buildList(const int *sortArray, const int &length) {
if (length < 0) {
return;
}
head = new Node<T>;
head->data = sortArray[0];
Node<T> *current = head;
for (int i = 1; i < length; ++i) {
Node<T> *tem = new Node<T>;
tem->data = sortArray[i];
tem->next = NULL;
current->next = tem;
current = tem;
}
}
int main() {
int sortArray[9] = { 0,1,2,4,5,6,7,8,9 };
listStruct<int> sortList;
sortList.buildList(sortArray, 9);
sortList.addNode(-1);
sortList.addNode(10);
sortList.displayList();
while (1){
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
示例二
给定一个链表的头结点head,再给定一个数num,请把链表调整成节点值都小于num的节点都放在链表的左边,值等于num的节点都放在链表的中间,值大于num的节点,都放在剪标的右边。
分析:将原链表分为三个链表,大于num,等于num,小于num。然后再将三个链表串起来。
#include<iostream>
#include<thread>
using std::endl;
using std::cout;
template<typename T> struct Node{
T data;
Node<T> *next;
};
template<typename T> class listStruct {
public:
listStruct() = default;
listStruct(Node<T> *h) : head(h) {}
~listStruct() {
Node<T> *temNext;
while (head){
temNext = head;
head = head->next;
delete temNext;
}
}
void buildList(const int *sortArray, const int &length);
void displayList();
void addNode(const int &data);
void sortList(const int &data);
void outputNode(Node<T> *node);
private:
Node<T> *head;
};
template<typename T> void listStruct<T>::outputNode(Node<T> *node) {
cout << "open" << endl;
while (node){
cout << node->data << endl;
node = node->next;
}
cout << "close" << endl;
}
template<typename T> void listStruct<T>::sortList(const int &data) {
Node<T> *temLess = new Node<T>;
Node<T> *temGreater = new Node<T>;
Node<T> *temEqual = new Node<T>;
Node<T> *lessList = temLess;
Node<T> *greaterList = temGreater;
Node<T> *equalList = temEqual;
Node<T> *tem = head;
while (tem){
if (tem->data < data) {
lessList->next = tem;
lessList = lessList->next;
tem = tem->next;
}
else if (tem->data == data) {
equalList->next = tem;
equalList = equalList->next;
tem = tem->next;
}
else {
greaterList->next = tem;
greaterList = greaterList->next;
tem = tem->next;
}
}
lessList->next = NULL;
greaterList->next = NULL;
equalList->next = NULL;
if (temLess->next) {
head = temLess->next;
tem = head;
while (tem->next){
tem = tem->next;
}
}
if (temEqual->next) {
tem->next = temEqual->next;
while (tem->next){
tem = tem->next;
}
}
if (temGreater->next) {
tem->next = temGreater->next;
}
delete temLess;
delete temGreater;
delete temEqual;
}
template<typename T> void listStruct<T>::addNode(const int &data) {
Node<T> *newNode = new Node<T>;
newNode->data = data;
newNode->next = NULL;
if (head == NULL) {
head = newNode;
}
if (head->data > data) {
newNode->next = head;
head = newNode;
return;
}
Node<T> *tem = head;
Node<T> *last = NULL;
while (tem) {
if (tem->data > data){
newNode->next = tem;
last->next = newNode;
return;
}
last = tem;
tem = tem->next;
}
last->next = newNode;
}
template<typename T> void listStruct<T>::displayList() {
Node<T> *tem = head;
cout << "start:" << endl;
while (tem){
cout << tem->data << endl;
tem = tem->next;
}
cout << "end!" << endl;
}
template<typename T> void listStruct<T>::buildList(const int *sortArray, const int &length) {
if (length < 0) {
return;
}
head = new Node<T>;
head->data = sortArray[0];
Node<T> *current = head;
for (int i = 1; i < length; ++i) {
Node<T> *tem = new Node<T>;
tem->data = sortArray[i];
tem->next = NULL;
current->next = tem;
current = tem;
}
}
int main() {
int sortArray[9] = { 9,1,2,6,5,7,4,8,0 };
listStruct<int> sortList;
sortList.buildList(sortArray, 9);
sortList.sortList(5);
sortList.displayList();
while (1){
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
示例三
给定两个有序链表的头结点,打印公共部分。
template<typename T> void printSameElement(Node<T> *head1, Node<T> *head2) {
if (!head1 || !head2){
return;
}
cout << "in" << endl;
while (head1&&head2){
if (head1->data == head2->data) {
cout << head1->data << endl;
head1 = head1->next;
head2 = head2->next;
}
else if (head1->data > head2->data) {
head2 = head2->next;
}
else {
head1 = head1->next;
}
}
}
示例四
给定一个单链表的头结点head,实现一个调整单链表的函数,使得每K个节点之间逆序,如果最后不够k个节点一组,则不调整最后几个节点。
template<typename T> Node<T> *reverseK(Node<T> *head,const int &k) {
if (!head) {
return head;
}
int i = 0;
Node<T> *tem = head;
Node<T> *start = head;
Node<T> *end = head;
bool firstFlag = true;
while (tem) {
++i;
if (i == 1) {
start = end;
}
if (i == k) {
i = 0;
end = tem;
if (firstFlag) {
Node<T> *temFront = head;
Node<T> *temEnd;
head = head->next;
temFront->next = end->next;
while (head != end) {
temEnd = head->next;
head->next = temFront;
temFront = head;
head = temEnd;
}
temEnd = head->next;
head->next = temFront;
firstFlag = false;
tem = start;
end = tem;
}
else {
Node<T> *temFront = start->next;
Node<T> *temEnd;
Node<T> *temCurrent = temFront->next;
tem = temFront;
if (end->next) {
temFront->next = end->next;
}
else {
temFront->next = NULL;
}
while (temCurrent != end) {
temEnd = temCurrent->next;
temCurrent->next = temFront;
temFront = temCurrent;
temCurrent = temEnd;
}
temCurrent->next = temFront;
start->next = temCurrent;
end = tem;
}
}
tem = tem->next;
}
return head;
}
示例五
给定一个单链表的头节点head,链表中每个节点保存一个整数,再给定一个值val,把所有等于val的节点删掉。
分析:重新构建一个链表,不等于val就接到新链表后,如果等于就抛弃。注意边界条件。
template<typename T> Node<T> *eliminateValue(Node<T> *head, const T &value) {
Node<T> *newHead = NULL;
Node<T> *temNode = new Node<T>;
temNode->next = NULL;
newHead = temNode;
while (head) {
if (head->data != value) {
newHead->next = head;
newHead = newHead->next;
}
head = head->next;
}
if (temNode->next) {
newHead = temNode->next;
}
else {
newHead = NULL;
}
delete temNode;
return newHead;
}
示例六
判断一个链表是否为回文结构。
分析:
方法一:空间复杂度为
O
(
N
)
O(N)
O(N)。采用一个栈保存前半段的数据,然后跟后半段的数据依次对比。
采用一个慢指针一次走一步与一个快指针一次走两步的方法可以确定链表中点位置。
template<typename T> bool plalindrome(Node<T> *head) {
std::stack<T> temStack;
if ((!head) || (!head->next)) {
return false;
}
Node<T> *fast = head;
Node<T> *slow = head;
bool middleFlag = false;
while (slow){
if (!middleFlag) {
if (!fast) {
middleFlag = true;
continue;
}
if (!fast->next) {
middleFlag = true;
slow = slow->next;
continue;
}
fast = fast->next;
fast = fast->next;
temStack.push(slow->data);
//cout << "stack push: " << temStack.top() << endl;
slow = slow->next;
}
else {
//cout << "slow data: " << slow->data << endl;
if (slow->data != temStack.top()) {
return false;
}
else{
//cout << "stack pop: " << temStack.top() << endl;
temStack.pop();
slow = slow->next;
}
}
}
return true;
}
方法二:空间复杂度为 O ( 1 ) O(1) O(1)。将后半部分倒叙指向,然后从两端开始遍历是非相等。最后要恢复链表原序。
template<typename T> bool plalindromeNoSpace(Node<T> *head) {
std::stack<T> temStack;
if ((!head) || (!head->next)) {
return false;
}
Node<T> *fast = head;
Node<T> *slow = head;
Node<T> *middleNode = head;
Node<T> *endNode;
bool middleFlag = false;
bool evenFlag = false;
while (slow) {
if (!middleFlag) {
if (!fast) { //偶
middleFlag = true;
middleNode = slow;
evenFlag = true;
break;
}
if (!fast->next) { //奇
middleFlag = true;
slow = slow->next;
middleNode = slow;
evenFlag = false;
break;
}
fast = fast->next;
fast = fast->next;
if (!fast) {
middleFlag = true;
middleNode = slow;
evenFlag = true;
break;
}
if (!fast->next) {
middleFlag = true;
slow = slow->next;
middleNode = slow;
evenFlag = false;
break;
}
slow = slow->next;
}
}
slow = middleNode;
Node<T> *newEnd = slow;
Node<T> *newHead;
slow = slow->next;
while (slow->next) {
newHead = slow->next;
slow->next = newEnd;
newEnd = slow;
slow = newHead;
newHead = slow->next;
}
bool result = true;
endNode = slow;
slow->next = newEnd;
middleNode->next = NULL;
listStruct<T>::outputNode(head);
listStruct<T>::outputNode(endNode);
Node<T> *left = head;
Node<T> *right = endNode;
while (right!=middleNode){
if (right->data != left->data){
result = false;
}
right = right->next;
left = left->next;
}
Node<T> *temCurrent = endNode->next;
newEnd = endNode;
while (temCurrent != middleNode) {
newHead = temCurrent->next;
temCurrent->next = newEnd;
newEnd = temCurrent;
temCurrent = newHead;
}
middleNode->next = newEnd;
endNode->next = NULL;
listStruct<T>::outputNode(newEnd);
return result;
}
示例七
如何判断一个链表是否有环,如果有环的话返回进入环的第一个节点,无环的话返回空,如果链表的长度为N,请做到时间复杂度为
O
(
N
)
O(N)
O(N),空间复杂度为
O
(
1
)
O(1)
O(1).
分析:使用快慢指针,慢指针一次走一步,快指针一次走两步。如果相遇则为有环,如果快指针指向NULL则无环。若有环,让快指针从头结点开始重新一次一步走,快慢指针再次相遇的位置为环的第一个节点。
示例八
如何判断两个无环单链表是否相交,如果相交的话返回第一个相交的节点,不相交的话返回空,如果两个链表的长度分别为N与M,请做到时间复杂度为
O
(
N
+
M
)
O(N+M)
O(N+M),额外空间复杂度为
O
(
1
)
O(1)
O(1)。
分析:遍历一遍两个链表,如果N>M,则第一个链表从N-M处,第二个链表从头节点开始遍历,对比两个节点是否相同。
示例九
如何判断两个有环单链表是否相交,如果相交的话返回第一个相交的节点,不相交的话返回空,如果两个链表的长度分别为N与M,请做到时间复杂度为
O
(
N
+
M
)
O(N+M)
O(N+M),额外空间复杂度为
O
(
1
)
O(1)
O(1)。
分析:首先找到两个链表的入环节点,如果入环节点相同,则按照无环链表找第一个相交节点的方法找到第一个相交点。如果入环节点不同可分为如下两种类型。
遍历第一个环,若找不到第二个环的入环节点,则为情况一,若找到第二个环的入环节点则为情况二,情况二随便返回任意一个入环节点均可。