数据结构 --链表
一直想把写过的数据结构给整理下来,很久没写了。先分享下写过的链表操作相关的比较有趣的题(代码都是可以运行的)。后续会补充
1. 经典问题,链表中环的问题,我有一篇博客专门解释环的问题,这里就不啰嗦了,也就是快慢指针的原理。直接上代码:
环的入口:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* p1=pHead;
ListNode* p2=pHead;
// ListNode* p3=pHead;
if(pHead==NULL||pHead->next==NULL)
return NULL;
do{
p1=p1->next;
p2=p2->next->next;
}while(p2!=NULL&&p2->next!=NULL&&p1!=p2);
if(p1==p2)
{
p2=pHead;
while(p2!=p1)
{
p2=p2->next;
p1=p1->next;
}
return p1;
}
return NULL;
}
};
2.约瑟夫圈圈问题(m>n可以)
已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
通常解决这类问题时我们把编号从0~n-1,最后[1] 结果+1即为原问题的解。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* p1=pHead;
ListNode* p2=pHead;
// ListNode* p3=pHead;
if(pHead==NULL||pHead->next==NULL)
return NULL;
do{
p1=p1->next;
p2=p2->next->next;
}while(p2!=NULL&&p2->next!=NULL&&p1!=p2);
if(p1==p2)
{
p2=pHead;
while(p2!=p1)
{
p2=p2->next;
p1=p1->next;
}
return p1;
}
return NULL;
}
};
3.合并两个排序的链表
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
/*
struct ListNode {
intval;
structListNode *next;
ListNode(intx) : val(x),next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1==NULL)
return pHead2;
if(pHead2==NULL)
return pHead1;
ListNode* pHead=NULL; //保存新的头结点
ListNode* p1=pHead1; //为了写的方便,就将p1.p2替换原来的两个头结点
ListNode* p2=pHead2;
ListNode* pre=pHead1;
ListNode* pT=NULL;
if(p2->val<=p1->val){ //确定头结点
pHead = p2;
p2=p2->next;
pHead->next=p1;
pre = pHead;
}
else{
pHead =p1;
p1=p1->next;
pre =pHead;
}
//将2插入1中
while(p1!=NULL&&p2!=NULL){
if(p2->val<p1->val){
pT=p2;
p2=p2->next;
pre->next=pT;
pT->next=p1;
}
else{
pre=p1;
p1=p1->next;
}
}
if(p1==NULL&&p2!=NULL){
pre->next = p2;
p2=p2->next;
}
if(p2==NULL&&p1!=NULL) {
pre->next = p1;
p1=p1->next;
}
return pHead;
}
};
4. 从尾到头打印链表(面试题中经常会问的问题,写之前先问清楚是否可以改变链表的结构)
输入链表的表头,输出为需要打印的“新链表”的表头
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
修改链表结构:
class Solution {
public:
vector<int> printListFromTailToHead(struct ListNode* head) {
vector<int> list1;
if(head == NULL){
return list1;
}
if(head->next==NULL)
{
list1.push_back(head->val);
return list1;
}
ListNode* pri = head;
ListNode* cur = head->next;
pri->next = NULL;
ListNode* q = NULL;
while(cur->next!=NULL)
{
q = cur;
cur =cur->next;
q->next = pri;
pri=q;
}
cur->next=pri;
while(cur)
{
list1.push_back(cur->val);
cur =cur->next;
}
return list1;
}
};
利用栈(只不过内存消耗大,不推荐):
class Solution {
public:
vector<int> printListFromTailToHead(struct ListNode* head) {
vector<int> list1;
if(head == NULL)
return list1;
stack<int> stack1;
while(head)
{
stack1.push(head->val);
head =head->next;
}
while(!stack1.empty()){
list1.push_back(stack1.top());
}
return list1;
}
};
只是逆序输出结点,不产生新表(递归):
vector<int>printListFromTailToHead(struct ListNode* head) {
vector<int> v;
while(head != NULL)
{
v.insert(v.begin(),head->val);
head = head->next;
}
return v;
}
class Solution {
public:
vector<int> list1;
vector<int> printListFromTailToHead(struct ListNode* head) {
if(head==NULL)
return list1;
list1=printListFromTailToHead(head->next);
list1.push_back(head->val);
return list1;
}
};
5.反转链表
输入一个链表,反转链表后,输出链表的所有元素
/*
struct ListNode {
intval;
structListNode *next;
ListNode(intx) :
val(x),next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if(pHead == NULL) return NULL;
if(pHead->next==NULL) return pHead;
ListNode* pri = pHead;
ListNode* cur = pHead->next;
pri->next = NULL;
ListNode* q = NULL;
while(cur->next!=NULL)
{
q = cur;
cur =cur->next;
q->next = pri;
pri=q;
}
cur->next=pri;
return cur;
}
};
//栈
void print(listNode* head)
{
std::stack<listNode*>nodes ;
listNode* pnode = head ;
while(pnode!=NULL)
{
nodes.push(pnode);
pnode = pnode->next;
}
while(!nodes.empty())
{
listNode* p = nodes.top();
cout<<p->data<<endl;
nodes.pop();
}
}
//递归
void print(listNode* head)
{
if(head!= NULL)
{
if(head->next != null)
{
print(head->next);
}
printf("%d\t",head->data);
}
}
6.设有一个带表头结点的双向循环链表L,每个结点有4个数据成员:指向先驱结点的指针prior、指向后继结点的指针next、
存放数据的成员data和访问频度freq。所有结点的freq初始时都为0.每当在链表上进行一次L.Locate(x)操纵时,
令元素值x的结点的访问频度freq加1,并将该结点前移,
链接到现它的访问频度相等的结点后面,使得链表中所有结点保持按访问频度递减的顺序排列,以使频繁访问的结点总是靠近表头。
voidLocate(int &x)
{
<结点类型说明 >
*p =first->next;
while (p != first && p->data!=x ) p = p->next;
if(p != first)
{
p->freq++ ;
<结点类型说明 >
*current = p;
current->prior->next = current->next;
current->next->prior =current->prior;
p =current->prior;
while (p != first && p->freq <current->freq ) p = p->prior;
current->next = p->next ;
current->prior = p;
p->next->prior = current;
p->next = current;
}
else
printf(“Sorry. Not find!\n”); \*没找到*\
}
7.输入一个链表,输出该链表中倒数第k个结点。
/*
struct ListNode {
intval;
structListNode *next;
ListNode(intx) :
val(x),next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if(pListHead==NULL||k==0)
return NULL;
ListNode* p_temp = pListHead; //一条用于从头遍历到k-1的位置
ListNode* q = pListHead;
int i=0;
while( i<k-1) {
p_temp = p_temp->next;
i++ ;
if(p_temp == NULL)
return NULL;
}
while(p_temp->next!=NULL){
p_temp = p_temp->next;
q= q->next;
}
return q;
}
};