剑指Offer面试题5反向打印链表

面试题5:反向打印链表。

输入一个链表的头结点,从尾到头打印每个节点的值(打印操作一般不改变链表的结构)。

思路1:典型的后进先出,用栈。

思路2:能用栈就能用递归(层数太深容易溢出),访问到一个节点后,递归输出它后面的节点,再输出该节点自身。

提供了java和c的两种实现。

先看java的:

public class PrintListReversingly {
	//尾插法建立链表,传入参数为头结点(头结点本身没有值)
	static ListNode createList(ListNode headNode){
		ListNode p = headNode;
		//确定头结点是否为空
		if(p == null){
			System.out.println("输入头结点为空,请检查。");
			return null;
		}else{
			Scanner sc = new Scanner(System.in);
			System.out.println("输入链表的值,以0结束:");
			int n = sc.nextInt();
			while(n != 0){
				//q为要插入的新节点
				ListNode q = new ListNode();
				q.data = n;
				q.next = null;
				p.next = q;
				//p始终指向最后一个结点
				p = q;
				n = sc.nextInt();
			}
			sc.close();
		}
		return headNode;
	}
	//从尾到头打印,用栈。
	static void print(ListNode headNode){
		Stack<ListNode> stack = new Stack<>();
		//这里假设不输出头结点。
		while(headNode != null && headNode.next != null){
			stack.push(headNode.next);
			headNode = headNode.next;
		}
		while(!stack.isEmpty()){
			System.out.println(stack.pop().data);
		}
	}
	public static void main(String[] args) {
		ListNode test = new ListNode();
		//ListNode test = null;
		print(createList(test));
	}
}
class ListNode{
	int data;
	ListNode next = null;
}
//递归方法,仅供参考,返回的arrayList已经是倒序了。
//public ArrayList<Integer> print2(ListNode headNode){
//	ArrayList<Integer> arrayList = new ArrayList<>();
//	if(headNode != null){
//		print2(headNode.next);
//		arrayList.add(headNode.data);
//	}
//	return arrayList;
//}

以下是c实现:

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

//定义linklist结构体类型
typedef struct linklist
{
    int data;
    linklist* next;
}list,*plist;//建立一个linklist类型的结构体list和一个指向linklist类型的指针plist

//尾插法建链表
void tail_insert(plist* headnode, int num)//如果传入的形参是一个指针p,修改指针指向的内存(也就是*p)会影响实参。
//此时形参headnode是一个二级指针,修改它指向的内存(也就是*headnode,等于实参指针head)就是直接修改实参head。
//还有一种效果相同的方法是:调用时传入实参指针即可,不用传地址了,定义函数形参时,也不用二级指针了,加个&即可。
//如:调用tail_insert(head, number),定义函数tail_insert(plist &headnode, int num),函数内可以直接使用headnode。
{
    plist p_new = (plist)malloc(sizeof(list));
    p_new->data = num;          //新元素data设为num
    p_new->next = NULL;         //将新元素next置为空
    plist temp = *headnode;         //每次执行函数时传入的headnode都是不变的,即头结点的地址,所以定义一个可变的指针变量指向头结点
    if (*headnode == NULL)          //头结点为空则赋予p_new为第一个新结点
    {
        *headnode = p_new;
    }
    else                            //若非空
    {
        while (temp->next != NULL)  //temp始终指向尾结点
        {
            temp = temp->next;
        }
        temp->next = p_new;     //将尾结点temp的next设为p_new,即将p_new设为尾结点
    }
}

//反向打印输出链表(递归)
void print_list(plist headnode)
{
    plist elem = headnode;
    if(elem->next!=NULL)
    {
		print_list(elem->next);
    }
	printf("%d ",elem->data);
    printf("\n");
}

void main()
{
    int number;
    plist head;
    head = NULL;//初始化表头为空

    printf("输入链表值,以-1结束:\n");
    scanf("%d",&number);
    while (number != -1)//输入-1终止输入循环
    {
	//为了能在函数内改变外部变量的值,传参时要传递实参的地址,因为head是指针变量所以形参要声明为二级指针。当然这只是一种方法。
        tail_insert(&head, number);
        scanf("%d", &number);
    }

    printf("反向打印输出链表(递归):\n");
    print_list(head);

    system("pause");
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值