C语言单向链表(头插、尾插、遍历、删除、反转)

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

typedef struct  NODE
{
    int data;
    struct NODE *next;    
}node;
/*
node *createlist_tail(void)
{
    node * head;
    head = NULL;
    node *p;
    int data;
    while (1){
        node *s = (node*)malloc(sizeof(node));
        printf("please input int data:");
        scanf("%d", &data);
        if(data == 0) break;
        s->data = data;
        printf("data=%d\n", s->data);
        if(head == NULL){
            head = s;//第一个节点来时,让头指针指向新节点
        }
        else{
            p->next = s;//之后的节点来时,让P->next指针指向新节点
        }
        p = s;
    }
    if(head != NULL){//因为有了新节点,所以head指针就不是指向NULL了
        p->next = NULL;//尾插法P->next永远在尾巴上,最后之向NULL
    }
    return head;
}
*/

node *createlist_tail(void)
{
    node *head = (node*)malloc(sizeof(node));
    node *p = head;//必须有,不然会崩,这里指向head,后面对p的操作等同于操作head
    head->next = NULL;//加或不加不影响
    // head = NULL;//这句一定不能加
    int data;
    while (1)
    {
        node *s = (node*)malloc(sizeof(node));
        printf("please input data:");
        scanf("%d", &data);
        if(data == 0) break;
        s->data = data;
        printf("data=%d\n", s->data);
        p->next = s;
        p = s;
    }
    head = head->next;//不加遍历就会把头结点算进去
    p->next = NULL;//尾插的最后指向NULL
    return head;
}

node *createlist_head(void)
{
    node *head = (node*)malloc(sizeof(node));
    head->next = NULL;//头插的这一句话至关重要
    // head->data = 0;
    int data;
    while (1)
    {
        printf("please input data:");
        scanf("%d", &data);
        if(data == 0) break;
        printf("data=%d\n", data);
        node *s = (node*)malloc(sizeof(node));
        s->data = data;
        /*最开始head->next是指向NULL的,因为是头插,所以第一个来的节点就是尾巴,这里让第一个节点保存head->next
        就相当于让第一个节点的next指向NULL,后面再来的节点就不会指向NULL了*/
        s->next = head->next;
        head->next = s;//让头结点更改方向指向新节点,这里不能是head->next=s->next,不然就成环了
        // s = s->next;//加不加无所谓   
    }
    head = head->next;//不加的话,遍历会把头结点算进去
    return head;
}

void print(node *head)
{
    while (head != NULL)
    {
        printf("output=%d\n", head->data);
        head = head->next;
    }
}

void print_t(node *head)
{
    node *p = head->next;
    printf(":%d\n", head->data);
    while (p != NULL)
    {
        printf("=%d\n", p->data);
        p = p->next;
    }
    // printf("=%d\n", head->data);
    // while (head->next != NULL)
    // {
    //     printf("out=%d\n", head->data);
    //     head = head->next;
    // }
}

int getlenlist(node *head)
{
    int len = 0;
    while (head != NULL)
    {
        head = head->next;
        len++;
    }
    return len;    
}
#if 0 
node *reverselist(node *head)
{
    if (head == NULL || head->next == NULL) return NULL;
	node *beg = NULL;
	node *mid = head;
	node *end = head->next;
	while (1){
		mid->next = beg;
		if (end == NULL){
			bread;
		}
		beg = mid;
		mid = end;
		end = end->next;
	}
	head = mid; // mid最后肯定指向了原先的尾巴,也就是现在的头,那么将head指向mid,返回就完成了反转
    return head;
}
#endif
node *reverselist(node *head)
{
    if(head == NULL || head->next == NULL) return head;
    // 这一步包含了很多信息,reverselist函数返回的是一个指针,指针指向了头结点
    node *p = reverselist(head->next);
    // 明白了上面那一步,这一步就好理解了,将尾结点的next指针指向尾结点的前一个结点
    head->next->next = head;
    // 将尾结点的前一个结点的next指针指向NULL
    head->next = NULL;
    // 开始递归,直到链表的头结点变成尾结点结束
    return p;
}
#endif
node *delete_node(node *head, int addr)
{
	node *temp = head;
	node *del = NULL;
	int i = 0;
	for (i = 1; i < addr; i++){
		temp = temp->next;
	}
	del = temp->next;
	temp->next = temp->next->next;
	free(del);
	return head;
}

int main(int argc, char const *argv[])
{
#if 1
    node * p = createlist_tail();
    // node *p = createlist_head();
    print(p);
    int len = getlenlist(p);
    printf("len=%d\n", len);
    p = reverselist(p);//递归方法需要用指针接收
    print_t(p);
    len = getlenlist(p);
    printf("len=%d\n", len);
#endif
    return 0;
}

头插与尾插的区别已经做了注释,反转有循环与递归,递归的写法简洁了很多。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值