单链表遍历一次求倒数第k个结点和中间结点

单链表:数据结点是单向排列的。

一个单链表结点,其结构分为两部分:数据域和指针域(用来存储其直接后继的地址)。例如:

typedef struct node{
    char name[20];
    struct node * next;
}student;
上述代码定义了一个单链表的结点,其中字符型数组char name[20]用来存储姓名。指针*link是一个用来存储其直接后继的指针。

单链表中每个结点的地址是存储在其前驱结点的next域中,而开始结点无前驱,故应设头指针head指向其开始结点。

链表由头指针唯一确定,单链表可以用头指针的名字来命名。

求单链表倒数第k个节点:

常规做法

先遍历一次链表求出链表长度n,链表的倒数第k个节点即正数的第(n-k+1)个,但是这样需要遍历两次链表。

遍历一次链表的思路

1、定义两个指针p1和p2均指向链表头指针,p1先遍历链表,走(k-1)步,p2保持不变。

2、从第k步开始,同时移动两个指针,始终保持两个指针的距离为(k-1)。当p1到链表最后一个指针时,p2指向的恰好是链表倒数第k个节点。

代码实现

#include <iostream> 
#include <malloc.h>
using namespace std; 

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

/* 
* 遍历一遍就得到单链表的中间结点的方法 
* 思想:两个指针,一个每次走一步,另一个每次走两步,两步走完的时候,一步的就是结果 
*/ 
int getCenterNode(node *head)
{
	if(head -> next == NULL)//链表为空
		return -1;

	node* temp = head->next;
	node* twoTemp = head->next;//最开始两个指针应该指向第一个有数据的节点。head里面没有存储数据

	while(twoTemp -> next != NULL && twoTemp -> next -> next != NULL) {
		temp = temp -> next;
		twoTemp = twoTemp -> next ->next;
	}
	return temp -> data;//偶数个节点时,返回前一个节点的值
}

void displayList(node *head)
{
	cout << "List:"<< endl;
	node *p = head -> next;
	//node *p = head;
	while(p != NULL){
		cout << p -> data <<"  ";
		p = p-> next;
	}
	cout << endl;
}
/*求链表倒数第k个节点*/
node* kthNode(node *head,int k)
{
	node * p1,*p2;
	p1 = head -> next;//链表的第一个有数据的节点
	p2 = head -> next;

	for(int i = 1; i < k  && p2->next != NULL; i++){
		p2 = p2->next;
	}
	if(p2 -> next == NULL)
		return NULL;
	while(p2->next){//不是while(p2),否则会多向后挪动一个
		p1 = p1 -> next;
		p2 = p2 -> next;
	}
	return p1;
}
 int main()
{
	node *head, *tmp;
	int i;

	head = (node*)malloc( sizeof(node));
	head -> next = NULL;
	
	for(i = 1; i < 9; i++){//头插法,头指针没有数据,即head里面没有数据。所以输出数据的时候从head-> next->data开始
		tmp = (node*)malloc(sizeof(node));
		tmp -> data = i;
		tmp -> next = head -> next;
		head -> next = tmp;
	}

	displayList(head);
	cout<<getCenterNode(head)<<endl;
	node *p1 = kthNode(head, 4);
	cout << p1 -> data<<endl;
	return 0;
}
 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值