单向链表--找最值、删除重复值点、合并链表

1.单向链表的创建

typedef struct Node{//定义结构体 
	int data;			// 数据域 
	struct Node* next;	//指针域 
}Node;


Node* init_List(int list[], int n){//链表初始化 
	if(n == 0) return NULL;
	Node* head = NULL;
	Node* tail = NULL;
	for(int i = 0;i < n;i++){
		Node* newnode = (Node*)malloc(sizeof(Node));
		newnode->data = list[i];
		newnode->next = NULL;
		if(!head){
			head = newnode;
			tail = newnode;
		}
		else{
			tail=tail->next = newnode;
		}
	}
	return head;
}


void printlist(Node* head){ //打印链表 
	Node* temp = head;
	while(temp){
		printf("%d -> ",temp->data);
		temp = temp->next;	
	}
	printf("NULL\n");
}

2.单向链表寻找最值

Node* findMaxNode(Node* head) {//返回单向链表的最大值节点 
    if (head == NULL) {
        printf("链表为空\n");
        return NULL;
    }

    Node *maxNode = head;  // 初始最大节点为头节点
    Node *current = head->next;  // 从第二个节点开始遍历

    while (current) {
        if (current->data > maxNode->data) {
            maxNode = current;  // 更新最大节点
        }
        current = current->next;  // 移动到下一个节点
    }

    return maxNode;
}

3.有序单向链表删除重复元素

    如果单向链表是有序的且包含重复值,我们可以利用有序链表的特点来高效地删除所有重复的节点。由于链表是有序的,相同的值一定是连续的,因此只需要遍历一次链表,比较当前节点和下一个节点的值是否相同即可。

(1)删除所有重复节点

版本1:

Node* deleteDuplicates(Node* head){//单向链表有序且含有重复值,删除所有重复值节点
	if (head == NULL || head->next == NULL) {
        return head;  // 链表为空或只有一个节点,直接返回
    }
	Node *currnode, *prenode;
	currnode = head;
	while(currnode){
		if(currnode->next != NULL &&currnode->data == currnode->next->data){
			if(currnode == head){
				while(currnode->next != NULL &&currnode->data == currnode->next->data){
					prenode = currnode;
					currnode = currnode->next;
					free(prenode);
				}
				head = currnode->next;
				free(currnode);
				currnode = head;
			}
			else{
				while(currnode->next != NULL &&currnode->data == currnode->next->data){
					prenode->next = currnode->next;
					free(currnode);
					currnode=prenode->next;
				}
				prenode->next = currnode->next;
				free(currnode);
				currnode=prenode->next;
			}
		}
		else{
			prenode = currnode;
			currnode = currnode->next;
		}
	}
	return head;
}

    版本2(对版本1进行了逻辑优化):

Node* deleteDuplicates(Node* head) {//单向链表有序且含有重复值,删除所有重复值节点--plus
    if (head == NULL || head->next == NULL) {
        return head;  // 链表为空或只有一个节点,直接返回
    }

    Node *currnode = head;
    Node *prenode = NULL;

    while (currnode) {
        bool isDuplicate = false;

        // 检查当前节点与下一个节点是否有相同值
        while (currnode->next != NULL && currnode->data == currnode->next->data) {
            isDuplicate = true;
            Node *temp = currnode->next;
            currnode->next = temp->next;  // 跳过重复的节点
            free(temp);  // 释放重复节点
        }

        if (isDuplicate) {
            // 如果当前节点也是重复的,删除当前节点
            Node *temp = currnode;
            if (prenode == NULL) {
                // 如果重复的是头节点
                head = currnode->next;
            } else {
                prenode->next = currnode->next;  // 跳过当前重复节点
            }
            currnode = currnode->next;
            free(temp);
        } else {
            // 当前节点不是重复节点,继续前进
            prenode = currnode;
            currnode = currnode->next;
        }
    }

    return head;
}

示例:

int main(void)
{
	int list[] = {1, 1, 2, 3, 3, 3, 4, 5, 5, 6, 7, 7};
	int n = sizeof(list)/sizeof(list[0]);
	Node *head = init_List(list, n);
	printlist(head);
	head = deleteDuplicates(head);
	printlist(head);
}

结果为:1 -> 1 -> 2 -> 3 -> 3 -> 3 -> 4 -> 5 -> 5 -> 6 -> 7 -> 7 -> NULL
                2 -> 4 -> 6 -> NULL

(2)每个重复节点保留一个值

      要实现每个重复节点只保留一个值,我们只需要删除重复的节点并保留第一个出现的节点即可。因为链表是有序的,相同值的节点会相邻排列,所以只需要在遍历链表时删除后续的相同节点。

Node* deleteDuplicates_pro(Node* head){
	if (head == NULL || head->next == NULL) {
        return head;  // 链表为空或只有一个节点,直接返回
    }

    Node *currnode = head;

    while (currnode != NULL && currnode->next != NULL) {
        // 如果当前节点与下一个节点的值相同
        if (currnode->data == currnode->next->data) {
            Node *temp = currnode->next;  // 临时保存要删除的节点
            currnode->next = temp->next;  // 跳过下一个节点
            free(temp);  // 释放内存
        } else {
            // 如果值不同,继续往下走
            currnode = currnode->next;
        }
    }

    return head;
}

4.合并两个有序链表

Node* mergeTwoLists(Node* l1, Node* l2) {
    if (l1 == NULL) return l2;
    if (l2 == NULL) return l1;

    Node* head = NULL;  // 合并后链表的头节点
    Node* tail = NULL;  // 合并链表尾节点 

    // 初始化合并后的头节点
    if (l1->data <= l2->data) {
        head = l1;
        l1 = l1->next;
    } else {
        head = l2;
        l2 = l2->next;
    }
    tail = head;  // 头节点也是尾节点的初始值

    // 合并两个链表
    while (l1 != NULL && l2 != NULL) {
        if (l1->data <= l2->data) {
            tail->next = l1;
            l1 = l1->next;
        } else {
            tail->next = l2;
            l2 = l2->next;
        }
        tail = tail->next;  // 移动到下一个节点
    }

    // 连接剩余部分
    if (l1 != NULL) {
        tail->next = l1;
    } else {
        tail->next = l2;
    }

    return head;  
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值