zoukankan      html  css  js  c++  java
  • c++单链表冒泡排序(交换结点),链表增删改查,运算符重载

    #include <iostream>
    #include <stdlib.h>
    #include <time.h>
    #include <fstream>
    #include <string>
    
    using namespace std;
    
    //类
    class List
    {
    public:
    	//构造器初始化,生成头节点
    	List()
    	{
    		head = new Node;
    		head->next = NULL;
    	}
    
    	//成员函数
    	void createList();
    	void insertList(int data);
    	void travelList(int chance);
    	void input();
    	int  addNode();
    	void deleteData(int addNum);
    	void ifClear();
    	void clearList();
    	//重载下标
    	int operator[](int idx);
    	//重载+
    	friend List operator+(List& List_1, List& List_2);
    	//重载-
    	friend List operator-(List& List_1, List& List_2);
    	//重载<<
    	friend ostream& operator<<(ostream& os, List& list);
    	//重载>>
    	friend istream& operator>>(istream& is, List& list);
    	//冒泡排序
    	void bubbleSortList(List& list);
    private:
    	//数据成员
    	struct Node
    	{
    		int data; //数据域
    		struct Node* next;	//指针域
    
    	} *head;//头指针
    
    	int num;//链表元素个数
    };
    
    
    //头插法生成节点
    void List::insertList(int data)
    {
    	Node* cur = new Node;
    
    	//插入数据
    	cur->data = data;
    
    	//插入节点
    	cur->next = head->next;
    	head->next = cur;
    }
    
    //调用insertList输入数据,生成链表
    void List::input()
    {
    	cout << "请输入链表数量长度:";
    	cin >> num;
    	srand(time(NULL));
    	for (int i = 0; i < num; i++)
    	{
    		insertList(rand() % 100);
    	}
    }
    
    //任意位置插入节点
    int List::addNode()
    {
    	int d, idx;
    
    	cout << "请输入你要插入的节点数据:";
    	cin >> d;
    	cout << "请输入你要插入的节点位置: ";
    	cin >> idx;
    
    	Node* tp = NULL;
    	Node* link = head;
    
    	//寻找插入位置
    	if (idx<1 || idx>num + 1)
    	{
    		cout << "操作非法" << endl;
    		return num;
    	}
    	else
    	{
    		for (int i = 0; i < idx; i++)
    		{
    			tp = link;
    			link = link->next;
    		}
    
    		Node* cur = new Node;
    		tp->next = cur;
    		cur->data = d;
    		cur->next = link;
    		travelList(1);
    		return ++num;
    	}
    }
    
    ofstream mycout1("D:/text1.txt");
    ofstream mycout2("D:/text2.txt");
    //遍历链表并将数据存入文件
    void List::travelList(int chance)
    {
    	Node* temp = head->next;	//防止头指针地址改变
    	while (temp != NULL)
    	{
    		cout << temp->data << "  ";
    		if (chance == 1)
    			mycout1 << temp->data << "  ";
    		else
    			mycout2 << temp->data << "  ";
    		temp = temp->next;
    	}
    	cout << endl;
    }
    
    //删除节点
    void List::deleteData(int addNum)
    {
    	int i, j = 0;
    	cout << "请问您要删除第几个数据: ";
    	cin >> i;
    	Node* tp = NULL;
    	Node* link = head;//link为删除节点后面的一个节点,temp为删除节点
    
    	if (addNum < i || i < 0)
    		cout << "操作非法!!" << endl;
    	else
    	{
    		while (link->next)
    		{
    			tp = link->next; //第一个节点
    			j++;
    			if (i == j)   //找的删除的节点
    			{
    				link->next = tp->next;
    				delete tp;
    				break;
    			}
    			link = link->next;
    		}
    		travelList(1);
    	}
    
    }
    
    //清空链表
    void List::clearList()
    {
    	Node* tp = NULL;
    	Node* ph = head->next;
    
    	while (head->next)
    	{
    		tp = ph;
    		ph = ph->next;
    		delete tp;
    		head->next = ph;
    	}
    
    	travelList(1);
    	cout << endl;
    }
    
    //询问是否清空
    void List::ifClear()
    {
    	string i;
    
    	if (!head->next)
    	{
    		cout << "链表已清空!!!" << endl;
    	}
    
    	else
    	{
    		cout << "是否清空链表(是/否):";
    		cin >> i;
    
    		if (i == "是")
    		{
    			clearList();
    			cout << "链表清空完成!!!" << endl;
    		}
    		else
    			cout << "链表未清空!!!" << endl;
    	}
    }
    
    //冒泡排序
    void List::bubbleSortList(List& list)
    {
    	//求list链表长度len
    	int len=0;
    	//临时指针phead
    	Node* phead = list.head->next;
    	while (phead)
    	{
    		len++;
    		phead = phead->next;
    	}
    
    	//冒泡排序
    	for (int i=0;i<len-1; i++)
    	{
    		//phead指向头结点
    		phead = list.head;
    		//ph1指向首元结点
    		Node* ph1 = phead->next;
    		//ph2指向首元结点的后继
    		Node* ph2 = ph1->next;
    		//进入循环冒出最大的数
    		for (int j = 0; j < len - 1 - i; j++)
    		{
    			//如果前面的值大于后面的值则交换
    			if (ph1->data > ph2->data)
    			{
    				phead->next = ph2;
    				ph1->next = ph2->next;
    				ph2->next = ph1;
    
    				//结点交换后,ph1与ph2位置颠倒回来
    				Node* temp = ph1;
    				ph1 = ph2;
    				ph2 = temp;
    			}
    
    			//如果不需要交换,三指针移动
    			phead = phead->next;
    			ph1 = ph1->next;
    			ph2 = ph2->next;
    		}
    	}
    
    	//打印结点数据
    	phead = list.head->next;
    	while (phead)
    	{
    		cout << phead->data << " ";
    		phead = phead->next;
    	}
    	cout << endl;
    }
    
    //下标重载
    int List::operator[](int idx)
    {
    	//临时指针temp,为了防止头指针改变
    	Node* temp = head;
    	//如果下标小于链表长度进行取值
    	if (idx < num)
    	{
    		for (int i = 0; i < idx; i++)
    		{
    			temp = temp->next;
    		}
    	}
    	return temp->data;
    }
    
    //+ 重载
    List operator +(List & List_1, List & List_2)
    {
    	//由链表1生成链表3
    	List List_3;
    	//生成临时指针temp_1
    	List::Node* temp_1 = List_1.head->next;
    	//把链表1的值给链表3
    	while (temp_1)
    	{
    		List_3.insertList(temp_1->data);
    		temp_1 = temp_1->next;
    	}
    	//生成临时指针temp_2
    	List::Node* temp_2 = List_2.head->next;
    	//把链表2的值给链表3
    	while (temp_2)
    	{
    		List_3.insertList(temp_2->data);
    		temp_2 = temp_2->next;
    	}
    
    	return List_3;
    }
    
    //- 重载
    List operator -(List & List_1, List & List_2)
    {
    	//生成链表4
    	List List_4;
    	//生成临时指针temp_1,temp_2
    	List::Node* temp_1 = List_1.head->next;
    	List::Node* temp_2 = List_2.head->next;
    	//flag为1链表2有链表1的值,为0则没有
    	int flag = 0;
    	//比较链表一和链表二,不等就将数据存入List_4
    	while (temp_1)
    	{
    		//临时指针temp_2回溯
    		temp_2 = List_2.head->next;
    		while (temp_2)
    		{
    			//判断是否有相同值
    			if (temp_1->data == temp_2->data)
    			{
    				flag = 1;
    				break;
    			}
    			//指针移动
    			temp_2 = temp_2->next;
    		}
    		//没有相同值List_4则插入数据
    		if (!flag)
    		{
    			
    			List_4.insertList(temp_1->data);
    		}
    			
    		//指针移动,开始下一轮对比
    		temp_1 = temp_1->next;
    		flag = 0;
    	}
    	return List_4;
    }
    
    //重载<<
    ostream& operator<<(ostream & os, List & list)
    {
    	list.bubbleSortList(list);
    	return os;
    }
    //重载>>
    istream &operator>>(istream & is, List & list)
    {
    	int size, i=0;
    	cout << "(输入链表长度):";
    	is >> size;
    	//当i<size时录入数据
    	while (i < size)
    	{
    		int data;
    		is >> data;
    		//插入数据
    		list.insertList(data);
    		i++;
    	}
    	return is;
    }
    int main()
    {
    	//初始化,生成List_1
    	List List_1;
    	//输入链表长度
    	List_1.input();
    	//遍历链表,并存入text1文件
    	List_1.travelList(1);
    	//添加节点并返回总结点数
    	int addNum = List_1.addNode();
    	//删除节点
    	List_1.deleteData(addNum);
    	
    
    	//初始化,生成List_2
    	List List_2;
    	//输入链表长度
    	List_2.input();
    	//遍历链表,并存入text2文件
    	List_2.travelList(2);
    
    	//重载下标
    	cout << "取链表2的第二个元素:";
    	cout << List_2[2]<<endl;
    	//重载+
    	List List_3;
    	List_3 = List_1 + List_2;
    	cout << "两链表+为:";
    	List_3.bubbleSortList(List_3);
    	//重载-
    	List List_4;
    	List_4 = List_1 - List_2;
    	cout << "两链表-为:";
    	List_4.bubbleSortList(List_4);
    	//重载<<
    	cout << "cout<<List_4:";
    	cout << List_4 << endl;
    	//重载>>
    	List List_5;
    	cout << "cin>>List_5";
    	cin >> List_5;
    	cout << "链表List_5: " << List_5;
    
    	//询问是否清空链表1
    	List_1.ifClear();
    
    	//关闭打开的文件
    	mycout1.close();
    	mycout2.close();
    	return 0;
    
    }
    

      

            用类创建单链表时,可以将结构体封装为私有成员,在构造函数中初始化链表极为方便;链表的删除操作需要先进行遍历,并且遍历途中不能随意改变头结点的位置,所以在进行链表的操作时,皆需要临时变量防止头指针改变;除此之外,在进行冒泡排序时,需要画图理清逻辑,虽然比较过后,链表的连接方式改变了,但是ph1与ph2位置颠倒,需要互换回来,使下一次比较正常运行;运算符“+”号重载时,如果直接由链表1生成链表3,在进行减操作时,会发现链表1随链表3的改变而改变了,导致在进行“-”操作时出错,后在“+”操作时,对链表3进行逐一赋值,问题得到解决。总的来说,此次试验对友元函数和运算符重载有了新的收获,例如如果将”<<”重载,”<<”会根据你输出的内容来调用相应的函数,从而在使用cout时更为方便。

  • 相关阅读:
    三、Vue CLI-单页面
    width100%,设置padding或border溢出解决方法
    一、Linux平台部署ASP.NET、ASP.NET CORE、PHP
    二、Core授权-2 之.net core 基于Identity 授权
    一、doT.js使用笔记
    一、域名认证信息
    HB-打包
    一、模型验证CoreWebApi 管道方式(非过滤器处理)2(IApplicationBuilder扩展方法的另一种写法)
    python 写的几道题
    美团面试总结
  • 原文地址:https://www.cnblogs.com/huxiaobai/p/10698169.html
Copyright © 2011-2022 走看看