<队列>合并有序链表

合并有序链表eg:
  ↓_h1
  1 3 5 7 
  ↓↗↓↗↓↗↓
  2 4 6 8→9→10
  ↑_h2

                                                            ↓_p
  ↓_head1
  [数据1|P_next] [数据3|P_next] [数据5|P_next] [数据7|P_next]  Null
  ↑_P_node1   ↓  ↑      ↓                 ↓___↑         ↓___↑
              ↓  ↑      ↓
              ↓  ↑      ↓                                        ↓_q
  ↓_head2 ← ← ↓  ↑      ↓                                                         
  [数据2|P_next]  ↑  [数据4|P_next] [数据6|P_next] [数据8|P_next]  [数据9|P_next] [数据10|P_next]  NULL
  ↑_P_node1   ↓___↑            ↓___↑          ↓___↑          ↓___↑          ↓___↑           ↓___↑
                                                  ↑_tail
  把第一行放入链表
  把第二行放入链表

  定义pq分别指向两个链表数据域的内容,使用p和q的移动来访问两个链表
  遍历两个链表:依次比较两个链表数据域的内容
  合并两个链表

  灵活运用数据结构解决具体问题的思想
  自己重新写一套,多谢多练
int main(void)
{

    struct Node* p_head1 = NULL;
    create_list(1);
    create_list(3);
    create_list(5);
    create_list(7);

    // 把上面链表的头指针指向的地址赋值给新指针
    p_head1 = p_head;
    print_linklist(p_head1);

    // create时 p_head已经被更新了,后面需要继续使用所以这里需要被置位空
    p_head = NULL;

    struct Node* p_head2 = NULL;

    create_list(2);
    create_list(4);
    create_list(6);
    create_list(8);
    create_list(9);
    create_list(10);
    // 把上面链表的头指针指向的地址赋值给新指针
    p_head2 = p_head;
    print_linklist(p_head2);

    p_head = NULL;

    merge_linlist(p_head1, p_head2);


    // 打印合并后的值
	print_linklist(p_head);


	return 0;
}

merge_linklist.cpp


#include <iostream>
#include "merge_linklist.h"
using namespace std;


// 头指针指向整个链表的第一个节点的地址,插入数据时,不可移动
struct Node* p_head = NULL;
// 不断追加数据时需要尾指针,始终指向链表的末尾,插入数据时,可以移动
struct Node* p_tail = NULL;

// 创建节点
void create_list(unsigned int elem)
{
    // 节点的数据占用多大的空间就开辟多大的内存空间,返回void* 类型,需要强制转换为节点的类型
    struct Node* p_node = (struct Node *)malloc(sizeof(struct Node));// 节点地址被赋值给指针P
    // 初始化数据域
    p_node->elem = elem;
    // 初始化指针域,此时并没有串联节点,指针指向空
    p_node->p_next = NULL;

    // 若一个节点都没有放到链表中
    if(p_head == NULL)
        p_head = p_node;// 插入数据时,不可移动
    else
    // 第二次调用时:P_tail = p_node1 = 第一个节点的地址,相当于第一个节点的指针域指向第二个节点的节点地址(p_node1->p_next = p)
        p_tail->p_next = p_node;

    // 第一次赋值的是第一个节点地址(只有一个元素:头=尾),第二次赋值的是第二个节点地址
    p_tail = p_node;

/*
第一次调用create_list
  ↓_head = P_node1      ↓_tail = P_node1                       
  [数据1|指针]  Null
  ↑       ↓___↑      
  P_node1 P_next 

第二次调用create_list
    ↓_head    ↓_tail = P_node1
  [数据1|指针] [数据2|指针]  Null
  ↑       ↓___↑      ↓___↑      
  P_node1 P_next = P_node2

*/
}


// 在链表中插入节点:1.插入的位置,插入的值
void insert_node(int pos, unsigned int elem)
{

    // 前节点
    struct Node *pre;
    // 初始化前节点,从头开始
	pre = p_head;
    // 循环次数
	int i = 0;
    struct Node* p_new = (struct Node *)malloc(sizeof(struct Node));
  
     // 如果插入的位置是头节点 ,头节点没有前节点,
	if(pos == 0)
	{
        p_new->elem = elem;
        // 新节点的指针域指向头节点(原来头节点的地址)
		p_new->p_next = p_head;
        // 更新“让新节点作为头节点
		p_head = p_new;
	}
	else
	{
        // 遍历链表,从头开始找,直到找到指定位置的前节点
        // 如找到位置3,则循环两次,循环次数 = 位置 -1
		while(i < pos - 1)
		{
			pre = pre->p_next;
			i++;
		}// 1.跳出循序找到前节点
    
		p_new->elem = elem;

        // 2.前节点的指针域赋值(pos后节点的地址)给新节点的指针域
		p_new->p_next = pre->p_next;

        // 3.让pos前节点的指针域指向新节点的地址
		pre->p_next = p_new;

        // 链表末尾
		if(p_new->p_next == NULL)
            // 更新
			p_tail = p_new;

	}
}


void delete_node(int pos)
{
    // 前节点,要删除的节点
	struct Node *pre, *p_delet;
	pre = p_head;
	int i = 0;

    // 删除头节点
	if(pos == 0)
	{
        // 更新
		p_head = p_head->p_next;

        // 释放头节点
		free(pre);
	}
	else
	{
		while(i < pos - 1)
		{
			pre = pre->p_next;
			i++;
		}// 1.找到前节点

        // 2.前节点的指针域指向的是要删除的节点的地址
		p_delet = pre->p_next;

        // 3.让pos前节点的指针域指向要删除的节点地址(pos的后节点),相当于删除
		pre->p_next = p_delet->p_next;

        // 删除尾节点
		if(p_delet->p_next == NULL)
			p_tail = pre;// 更新
        // 释放当前要删除节点所占用的内存空间
		free(p_delet);
	}
}


// 显示链表数据域
void print_linklist(struct Node* linlist_head)
{
	struct Node *p;
	
    // p不为空的话就一直更新p的位置 ,循环条件:p != NULL
	for(p = linlist_head; p; p = p->p_next)
    cout << p->elem << " ";

	cout << endl;
}


int search(unsigned int elem)
{
	struct Node *p;

	for(p = p_head; p; p = p->p_next)
		if(p->elem == elem)
			return 1;
	return 0;
}


void merge_linlist(struct Node* p, struct Node* q)
{
    // p和q只要有一个为空就退出循环
    while(p && q)
    {
        // 遍历两个链表:依次比较两个链表数据域的内容
        if(p->elem <= q->elem)
        {
            // 若一个节点都没有放到链表中
            if(p_head == NULL)
                // 更新头
                p_head = p;// 第一次之后都不更改,不可移动
            else
                // 第二次赋值时:P_tail = p_node1,相当于p_node1->p_next = p_2
                p_tail->p_next = p;

            // 第一次赋值的是第一个节点地址(只有一个元素:头=尾),第二次赋值的是第二个节点地址
            p_tail = p;
            // 更新p,指向下一个节点
            p = p->p_next;
        }
        else
        {
            if(p_head == NULL)
                p_head = q;
            else
                p_tail->p_next = q;
            // 更新尾指针
            p_tail = q;
            // 更新q
            q = q->p_next;
        }
    }

    // 还剩9和10没有添加到节点数据域,若p为空则取q,不为空则取p
    p_tail->p_next = p ? p : q;// 指向9,9又关联10

}

merge_linklist.h

#ifndef LINKLIST_H__
#define LINKLIST_H__

#include <iostream>

// 声明一个外部变量,在其他文件可见可赋值
extern struct Node* p_head;
extern struct Node* p_tail;

struct Node
{
    // 数据域
    unsigned int elem;
    // 指针域
    struct Node* p_next;
};


void create_list(unsigned int elem);
void insert_node(int pos, unsigned int elem);
void delete_node(int pos);
void print_linklist(struct Node* linlist_head);
int search(unsigned int elem);

void merge_linlist(struct Node* p, struct Node* q);

#endif

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值