数据结构 | C++ | 快排和折半查找后插入

顺序表:

0.头文件

using namespace std;
#include <iostream>
#include<string>
#include<vector>

1.结点类和顺序表类: 

vector的好处就是析构函数只要:s.clear();

//结点类
struct Student
{
	int score;  
	string name;
};

//顺序表类
class Seqlist
{
public:
	Seqlist();															//构造函数
	~Seqlist() {s.clear();}											//析构函数
	int size();															//返回元素个数
	void Traverse();													//遍历函数

	void QuickSort(int i,int j);									//快排的递归调用
	int Partition(int i, int j);										//快排的一次划分算法

	void BiSearch();					//折半插入排序

private:

	vector <Student> s;
	int length;
};

 

2.构造函数

//构造函数
Seqlist::Seqlist()
{
	Student m;
	cout << "输入的学生成绩个数";
	cin >> length;//length  即为最大容量
	for (int i = 0; i < length; i++)
	{
		cout << "输入第" << i + 1 << "位学生姓名: ";
		cin >> m.name;
		cout << "输入" << i + 1 << "位学生成绩: ";
		cin >> m.score; cout << endl;

		s.push_back(m);
	}
}

 3.求表长,遍历函数

//返回元素个数
int Seqlist::size()
{

	return s.size();
}

//遍历函数
void Seqlist::Traverse() 
{
	for (int i = 0; i < s.size(); i++)//修改前:i<lenght,错在vector扩容一位后length未随之改变
	{
		cout << "第" << i + 1 << "位学生姓名:" << s[i].name << "	      " << "成绩:"<<s[i].score<<endl;
	}
}

 

*4.快排

temp指第一个元素,用来存放标记值;

i是0,表示表第一个元素;

j是length()-1,表示最后一个元素.

递归要避开枢轴,否则会溢出栈

③之前的bug:如int temp = s[i].score;改变了成绩的次序,未改变学生的次序

//快排的一次划分算法
int Seqlist::Partition(int i, int j)
{
	Student temp = s[i];        //将首元素的key设为关键字  
	while (i<j)
	{
		while (i < j&&s[j].score >= temp.score)
		{
			j--;				//j一直循环到一个小于temp的值
		}
		if (i<j)
		{
			s[i++] = s[j];//s[i]=s[j];  i++;
		}

		while (i<j&&s[i].score<=temp.score)
		{
			i++;				//i一直循环到一个大于temp的值
		}
		if (i < j)
		{
			s[j--] = s[i];
		}
	}
	
		s[i] = temp;
	
	return i;     //返回i即子表的大小
}
//快排的递归调用
void Seqlist::QuickSort(int i, int j)
{
	int pivot;//枢轴
	if (i < j)
	{
		pivot = Partition(i, j);
		QuickSort(i, pivot-1);	//before:	QuickSort(i, pivot);
		QuickSort(pivot+1, j);//before:	QuickSort(pivot, j);
	}

}

*5 折半查找

 



//折半查找算法
void Seqlist::BiSearch()
{
	int low = 0; 
	int high = s.size() - 1;
	int find = 0;
	int mid;

	Student m;
	cout << "输入新同学姓名";
	cin >> m.name;
	cout << "输入新同学成绩";
	cin >> m.score;

	if(m.score>s[s.size()-1].score)			//m.score大于最大的,直接尾部加入
	{
		s.push_back(m);//如果不是vector,而是数组,此处应该有length++;下面一样.
	}
	else if(m.score<s[0].score)				//m.score小于最小的,插入表头
	{ 
		s.insert(s.begin(), m);
	}
	else												//m.score的大小在数组范围内
	{
		while (low <= high&&find==0)
		{
			 mid = (low + high) / 2;

			 if (m.score < s[mid].score)
			 {
				 high = mid - 1;
				 if (low == mid)				//添加这样一个if(),才能将陌生元素加入顺序表
				 {
					 s.insert(s.begin() + mid , m);
				 }
				 find = 1;							//终止循环
			 }
			else if (m.score > s[mid].score)
			{
				low = mid + 1;
				if (low == mid)
				{
					s.insert(s.begin() + mid , m);
				}
				find = 1;							//终止循环
			}
			else										//插入值与数组某元素相等
			{
				 find = 1;							//终止循环
				 s.insert(s.begin() + mid, m);
			}	
		}	
	}
}


 

6.main()函数

int main()
{
	Seqlist s1;
	s1.Traverse();

	//顺序表快排测试
	s1.QuickSort(0, s1.size() - 1);
	cout << "快速排序后"<<endl;
	s1.Traverse();

	//顺序表折半查找插值算法
	s1.BiSearch();
	s1.Traverse();


	system("pause");
	return 0;
}

 


链式存储的排序算法:

0.头文件

using namespace std;
#include <iostream>
#include<string>

1.节点类和链表类: 

 为了在main()传参调用快速排序算法,不得不把Student *elem 改为public.


//结点类
struct Student
{
	 int score;  
	Student *next=nullptr;					//结点类的*next 需要初始化,否则显示"读取访问权限冲突"
};

//链表类
class Linklist
{
public:
	Linklist();															//构造函数
	~Linklist();															//析构函数
	void CreateLinklist();											//创建链表
	int size();															//返回元素个数
	void Traverse();													//遍历函数

	
	Student *Partition(Student *pBegin, Student *pEnd);										//快排的一次划分算法
	void QuickSort(Student *pBegin, Student *pEnd);									//快排的递归调用
	
	void BiSearch();					//折半插入排序


	Student *elem;
};

2.构造函数与析构函数 

①elem new出头结点后,不需要为其数据域赋初值,只要将next指针域置nullptr即可

//构造函数
Linklist::Linklist()
{
	elem = new Student;	
	elem->next = nullptr;				//常量NULL实际上是数字0,可能引起误用.作为解决方案,nullptr是代表空指针的字面值常量
}

//析构函数
Linklist::~Linklist()
{
	Student *p = elem;
	
	while (p)
	{
		Student *q = p;
		p = p->next;
		delete q;
	}
	elem = nullptr;
	//头删法
}

3.创建链表

  也可以写成带参构造函数.

//创建链表
void Linklist::CreateLinklist()
{
	Student *p, *q;
	p = elem; 
	 int n;
	cout << "输入学生个数\n";
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		q = new Student;

		cout << "输入" << i + 1 << "位学生成绩: ";
		cin >> q->score;cout << endl;
		p->next = nullptr;

		p->next = q;
		p = p->next;
	}
	cout << "输入成功!\n";
}

 4.表长和遍历


//学生个数
int Linklist::size()
{
	int i = 0;
	Student *p = elem->next;				//p指向首元结点
	while (p)
	{
		p = p->next;
		i++;
	}
	return i;
}

//遍历函数
void Linklist::Traverse()
{
	
	Student *q = elem->next;			//首元结点
	
	for (int i = 0; i < this->size(); i++)
	{
		cout << "第" << i + 1 << "位学生成绩:" << q->score << endl;
		q = q->next;
	}
	
}

*5链表类型的快排算法 

①i指针之前的值都小于标记值

i~j之间的值都大于标记值

j之后的值都未判断大小,当j==nullptr,意味着一次排序结束.

②※递归算法QuickSort(Student *pBegin, Student *pEnd) 中,

注意if()内的第一行,输入的

Partition(Student *pBegin, Student *pEnd)

形参来自于

QuickSort(Student *pBegin, Student *pEnd)

的形参,

究其根本,是由

main()中(a1.elem->next, nullptr)传递实参.

 




//快排的一次划分算法(两个指针均向后移动)
Student* Linklist::Partition(Student *pBegin, Student *pEnd)//pBegin的实参是elem,pEnd的实参是最末元素的next,也就是nullptr
{
	Student *i = pBegin;						//首元结点
	Student *j = i->next;
	int flag = pBegin->score;				//基准数字

	while (j != pEnd)									//循环到j是最后一个元素的next域(NULL状态)
	{
		if (j->score < flag)
		{
			i = i->next;
			
			swap(i->score, j->score);
		}
		j = j->next;
	}
	swap(i->score, pBegin->score);
	return i;
}

//快排的递归
void Linklist::QuickSort(Student *pBegin, Student *pEnd)
{
	if (pBegin!=pEnd) 
	{
		Student *pivot = Partition(pBegin,pEnd);				//此处输入的是形参
		QuickSort(pBegin, pivot);
		QuickSort(pivot->next, pEnd);
	}
}





6.main()

int main()
{

	Linklist a1;
	a1.CreateLinklist();

	//返回学生数
	cout << "学生有" << a1.size() << "位\n";

	//遍历
	a1.Traverse(); cout << endl;

	
	//快排
	a1.QuickSort(a1.elem->next, nullptr);
	cout << "快排后:\n";
	a1.Traverse();
	

	system("pause");
	return 0;
}

7.Bug

void Linklist::text()
{
    Student *p = elem->next;
    p->score = 100;
    Traverse();
}

错误,不能直接修改结点的值

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值