1、求单链表中有效节点个数
思路:遍历链表获取单链表的节点的个数(如果是带头节点的链表,不能统计头节点)
public static int getLength(LinkNode head)
{
if(head.next==null)
{
return 0;//空链表
}
int length=0;
//定义一个辅助的变量,这里我们没有统计头节点
LinkNode cur = head.next;
while(cur != null)
{
length++;
cur = cur.next;//继续向下遍历
}
return length;
}
2、查找单链表中的倒数第k个节点(新浪面试题)
思路:
- 编写一个方法,接收head节点,同时接收一个index值(即k的值)
- 先把链表从头到尾遍历,得到链表的总长度 ,用上一题的getLength()方法
- 得到长度size后,我们从链表的第一个开始遍历(size-index)个,就可以得到
- 如果找到了,返回该节点,否则返回null
public static LinkNode findLastIndexNode(LinkNode head,int index)
{
//判断如果链表为空,返回null
if(head.next == null)
{
return null;
}
//第一遍遍历得到长度
int size = getLength(head);
//第二次遍历size-index位置,就是倒数的第K个节点
//先做一个index校验
if(index <= 0 || index > size)
{
return null;
}
//定义一个辅助变量cur,for循环定位到倒数的index
LinkNode cur = head.next;
for(int i=0;i<size-index;i++)
{
cur = cur.next;//向后遍历
}
return cur;
}
3、单链表的反转(腾讯面试题)
思路:
- 先定义一个新的头节点reverseHead = new LinkNode();
- 从头到尾遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表头reverseHead.next上
- 原来的链表头head.next = reverseHead.next
public static void reversetList(LinkNode head)
{
//如果当前链表为空,或者只有一个节点,无需反转,直接返回
if(head.next == null || head.next.next == null)
{
return;
}
//定义一个辅助变量,帮助我们遍历原来的链表
LinkNode cur = head.next;
StudentLinkNode temp = null;//定义一个空的temp节点
LinkNode reverseHead = new LinkNode();
//遍历原来的链表,每遍历一个节点,就将其取出并放在新的reverseHead的后面第一个节点的位置
while(cur != null)
{
temp = cur.next;//空的temp节点暂时储存当前节点cur的下一个节点
cur.next = reverseHead.next;//将cur的下一个节点指向新的链表的最前端
reverseHead.next = cur;//将cur连接到新的链表上
cur = cur.next;
}
//将head.next指向reverseHead,next实现单链表的反转
head.next = reverseHead.next;
}
4、从尾到头打印单链表
思路:
- 这道题目要求的是逆序打印单链表
- 方式一:先将单链表进行反转操作,然后进行遍历即可,但是这样做的问题是会破坏原来的单链表的结构(不建议)
- 方式二:可以利用栈这个数据结构,将各个节点压入到栈中,然后利用栈的先进后出的特点,就实现了逆序打印的效果。
public static void reversePrint(LinkNode head)
{
if(head.next == null)
{
return;//空链表,不能打印
}
//创建一个栈,将各个节点压入栈中
Stack<LinkNode> Stack = new Stack<LinkNode>();
LinkNode cur = head.next;
//将链表的所有节点压入栈中
while(cur != null)
{
stack.push(cur);
cur = cur.next;//cur后移,这样就可以压入下一个节点
}
//将栈中的节点进行打印,pop出栈
while(stack.size()>0)
{
System,out.println(stack.pop());//stack的特点就是先进的后出
}
}
5、合并两个有序的单链表,合并之后的链表依然有序
思路:
- cur1 和cur2 分别是两条有序链表的辅助引用(指针)方便两个链表的遍历,result 则为合并之后的结果链表,tail为结果链表的最后一个节点,方便尾插
- cur1 和 cur2 同时往后走,两个引用所指的数分别比较,拿出来的节点尾插在result链表中
public static LinkNode mergeList(LinkNode node1,LinkNode node2)
{
//定义一个辅助变量cur1,帮助我们遍历第一条链表
LinkNode cur1 = node1;
//定义一个辅助变量cur2,帮助我们遍历第二条链表
LinkNode cur2 = node2;
LinkNode result = new LinkNode();//定义节点temp为合并后产生的新链表的头节点
//result 则为合并之后的结果链表头节点,tail为结果链表的最后一个节点,方便尾插
result = null;
ListNode tail = null;
//定义一个空的temp节点
ListNode next = null;
while((cur1 != null) && (cur2 != null))
{
if(cur1.data <= cur2.data)
{
if(result != null)//当结果链表不为空时
{
temp = cur1.next; // temp节点保存链表1的下一个节点,让循环可以继续
tail.next = cur1; // 插入过程
cur1.next = null;
tail = cur1; //保存结果链表的最后一个节点
cur1 = temp;
}
else
{ // 结果链表为空时
temp = cur1.next;
result = cur1;
cur1.next = null;
//保存新的最后一个节点
tail = cur1;
cur1 = temp;
}
}
else
{
if(result != null)
{
temp = cur2.next;
tail.next = cur2;
cur2.next = null;
tail = cur2;
cur2 = temp;
}
else
{
temp = cur2.next;
result = cur2;
cur2.next = null;
//保存新的最后一个节点
tail = cur2;
cur2 = temp;
}
}
}
//其中一个链表为空之后
//第一条链表的cur1走完以后,第二条链表的cur2还没走完就直接插到结果链表的尾部
if(cur1 == null)
{
tail.next = cur2;
}
//第二条链表的cur2走完以后,第一条链表的cur1还没走完就直接插到结果链表的尾部
if(cur2 == null){
tail.next = cur1;
}
return result;
}