面经 常见数据结构的算法 - 链表专题

总结常见链表题型

1.链表中倒数第k个结点

题目:输入一个链表,输出链表中倒数第k个节点,为了符合大多数人的习惯,本题从1开始计数,即链表的尾巴节点是倒数第一个节点。

方法1:先遍历链表得到链表的个数n,倒数第k个节点就是n-k+1再遍历一次链表,找到第n-k+1个节点就是倒数第k个节点;这种方法遍历两次链表;

方法2:先遍历链表把链表压入一个栈,再出栈,第k次出栈就是第k个节点;

方法3:先反转链表,再遍历

方法4:定义两个指针,第一个指针从链表的头指针开始遍历向前走k-1;第二个指针保持不动,从第k步开始,第二个指针也开始遍历,两个指针差距k-1个距离

2.两个链表升序的链表合并有递归和非递归方式。里面还有反转链表。

#ifndef _head_
#define _head_

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


using namespace std;

typedef struct ST_LinkTable
{
	int data;
	ST_LinkTable *next;
};

class LinkTable
{
public:
	LinkTable();
	~LinkTable();

	void test();
	//link1
	bool createLinkTable(ST_LinkTable* nodes);
	bool InsertTable(int data, ST_LinkTable * nodes);
	bool Insert(int data, ST_LinkTable * nodes);
	bool FindData(int data, ST_LinkTable * nodes);
	bool FindData_info(int data, int *pos, ST_LinkTable * nodes);
	int GetLength(ST_LinkTable* nodes);
	bool Delete(int data, ST_LinkTable * nodes);


	//link2
	bool createLinkTable1(ST_LinkTable* nodes);

	//merge
	//递归
	ST_LinkTable* mergeTable(ST_LinkTable *link1, ST_LinkTable *link2);
	//非递归
	ST_LinkTable* LinkTable::mergeTable1(ST_LinkTable *link1, ST_LinkTable *link2);

	//反转链表
	void TurnLinkTable(ST_LinkTable *link);

	

protected:


private:
	ST_LinkTable *head;
	ST_LinkTable *head1;
	
};





#endif
#include "head.h"
LinkTable::LinkTable()
{
}
LinkTable::~LinkTable()
{
}
bool LinkTable::createLinkTable1(ST_LinkTable* nodes)
{
	nodes = (ST_LinkTable*)malloc(sizeof(ST_LinkTable));
	if(nodes == NULL)
	{
		return false;
	}
	memset(nodes, 0, sizeof(ST_LinkTable));
	head1 = nodes;
	return true;

}

bool LinkTable::createLinkTable(ST_LinkTable* nodes)
{
	nodes = (ST_LinkTable*)malloc(sizeof(ST_LinkTable));
	if(nodes == NULL)
	{
		return false;
	}
	memset(nodes, 0, sizeof(ST_LinkTable));
	head = nodes;
	return true;

}

int LinkTable::GetLength(ST_LinkTable* nodes)
{
	ST_LinkTable *temp;
	temp = nodes;
	int len = 0;
	while(temp != NULL)
	{
		len++;
		temp = temp->next;
	}
	return len;
}

bool LinkTable::FindData(int data, ST_LinkTable * nodes)
{
	ST_LinkTable *temp = nodes;
	while(temp != NULL)
	{
		if(temp->data == data)
		{
			return true;
		}
		temp = temp->next;
	}
	return false;

}

bool LinkTable::Insert(int data, ST_LinkTable * nodes)
{
	ST_LinkTable* temp = nodes;
	int depth = GetLength(nodes) - 1;
	//find insert nodes
	int len = 0;
	while((temp != NULL) && (len < depth))
	{
		temp = temp->next;
		len++;
	}
	//Malloc new node
	ST_LinkTable* node = (ST_LinkTable*)malloc(sizeof(ST_LinkTable));
	if(node == NULL)
	{
		return false;
	}
	memset(node, 0, sizeof(ST_LinkTable));
	node->next = NULL;
	temp->next = node;
	temp->data = data;
}

bool LinkTable::InsertTable(int data, ST_LinkTable * nodes)
{
	//find data
	if(FindData(data, nodes))
	{
		//find data
		printf("Already Exists\n");
		return false;
	}
	else
	{
		//not find data Begin Insert
		Insert(data, nodes);
	}
}

bool LinkTable::FindData_info(int data, int *pos, ST_LinkTable * nodes)
{
	bool ret = false;
	ST_LinkTable *temp = nodes;
	int len = GetLength(nodes) - 1;
	int depth = 0;
	while((temp != NULL) && (depth < len))
	{
		if(temp->data == data)
		{
			ret = true;
			break;
		}
		depth++;
	}
	*pos = depth;
	return ret;
}

bool LinkTable::Delete(int data, ST_LinkTable * nodes)
{
	bool ret = false;
	ST_LinkTable *temp = nodes;
	ST_LinkTable *node;
	ST_LinkTable *delete_node;
	int pos = 0;
	ret = FindData_info(data, &pos, nodes);
	if(ret == false)
	{
		return ret;
	}

	int len = 0;
	if(pos == 0)
	{
		//head
		delete_node = head;
		head = head->next;
		free(delete_node);

	}
	else
	{
		while((temp != NULL) && (len < pos))
		{
			temp = temp->next;
		}
	
		node = temp->next->next;
		temp = node;
		delete_node = temp->next;
		free(delete_node);
	}

	


}

void LinkTable::test()
{
	createLinkTable(head);
	InsertTable(1,head);
	InsertTable(2,head);
	InsertTable(3,head);
	InsertTable(4,head);
	InsertTable(5,head);
	
	createLinkTable1(head1);
	InsertTable(2,head1);
	InsertTable(4,head1);
	InsertTable(6,head1);
	InsertTable(8,head1);
	InsertTable(10,head1);
	
	TurnLinkTable(head);
	//ST_LinkTable* temp = mergeTable(head,head1);

	ST_LinkTable* temp1 = mergeTable1(head,head1);
}

//合并链表 有两种 一种通过递归。另一种非递归方式




//递归方式
ST_LinkTable* LinkTable::mergeTable(ST_LinkTable *link1, ST_LinkTable *link2)
{
	if(link1 == NULL)
	{
		return link2;
	}
	if(link2 == NULL)
	{
		return link1;
	}
	ST_LinkTable * temp = NULL;

	if(link1->data < link2->data)
	{
		temp = link1;
		temp->next = mergeTable(link1->next, link2);
	}
	else
	{
		temp = link2;
		temp->next = mergeTable(link1, link2->next);
	}

	return temp;

}
//非递归方式 合并链表

ST_LinkTable* LinkTable::mergeTable1(ST_LinkTable *link1, ST_LinkTable *link2)
{
	if(link1 == NULL)
	{
		return link2;
	}
	if(link2 == NULL)
	{
		return link1;
	}

	ST_LinkTable* temp = (ST_LinkTable*)malloc(sizeof(ST_LinkTable));
	ST_LinkTable* node = temp;
	while((link1 != NULL) && (link2 != NULL))
	{
		if(link1->data < link2->data)
		{
			node->next = link1;
			link1 = link1->next;
		}
		else
		{
			node->next = link2;
			link2 = link2->next;
		}
		node = node->next;
	}

	if(link1 != NULL)
	{
		node->next = link1;
	}
	if(link2 != NULL)
	{
		node->next = link2;
	}

	return temp->next;


}

//
void LinkTable::TurnLinkTable(ST_LinkTable *link)
{
	ST_LinkTable *temp;
	ST_LinkTable *ph;
	ST_LinkTable *news = NULL;

	ph = link;
	while(ph != NULL)
	{
		temp = ph->next;
		//颠倒 节点
		//原来是1->2->3->4->5 颠倒节点 1<-2<-3<-4<-5 把1的节点用临时变量保存,存在2的下一个上。循环然后在3的下一个上存2的节点。依次类推就成反转了。
		//
		ph->next = news;
		news = ph;
		ph = temp;
	}

	int a = 0;
	return ;
}

3.反转链表

4.删除倒数第K个元素

方法1:遍历第一遍确定位置,第二遍开始删除。

方法2:用两个指针。第一个指针不动,下一个指针走倒数K个节点的个数。如果不是尾节点,循环直到找到倒数K节点。

5.删除链表中重复节点

点赞