链表实现排序算法
- 格式:docx
- 大小:219.95 KB
- 文档页数:19
空间复杂度为o(n)的排序算法作为计算机科学中的一个重要概念,计算机算法旨在解决一系列问题。
其中,排序算法是最基本的算法之一。
排序算法可以将一组无序的数据按照一定的规则排列,从而更方便地进行查找和使用。
在计算机科学中,我们常常会涉及排序算法,而空间复杂度为 O(n) 的排序算法是最为实用和高效的一种。
下面,我们将分步骤阐述这种算法。
第一步:选择适合数据集合的排序算法首先,我们需要根据数据集合的规模和特点来选择合适的排序算法。
由于我们要实现的是空间复杂度为 O(n) 的排序算法,因此我们应该优先考虑基于比较的排序算法。
常见的基于比较的排序算法有冒泡排序、插入排序、归并排序和快速排序。
其中,冒泡排序、插入排序和归并排序均可以实现 O(n) 的空间复杂度,而快速排序则需要使用递归实现,空间复杂度较高,不适合本题。
第二步:实现基于链表的插入排序算法插入排序是一种简单但高效的排序算法,对于小规模数据集的排序特别有效。
对于大部分排序算法而言,空间复杂度往往是 O(nlogn) 或 O(n^2) 级别的,但插入排序却很特别,它的空间复杂度为 O(n)。
这使得插入排序成为实现本题的最佳选择。
基于链表的插入排序算法的核心思想是将无序的链表中的节点依次插入到新的有序链表中。
我们可以创建一个新的空链表,遍历原链表,将每个节点按照一定的规则插入到新链表中。
在这个过程中,我们需要维护一些指针和计数器以保证算法正确执行。
第三步:实现归并排序算法另一种基于比较的排序算法是归并排序。
归并排序的核心思想是将原始数据分成两个有序子序列,然后将这些子序列合并成一个大的有序序列。
归并排序算法也可以实现 O(n) 的空间复杂度,但它的时间复杂度一般为 O(nlogn)。
基于链表的归并排序算法实现过程与基于数组的实现过程类似,只是需要更多的指针和代码逻辑来维护链表的特殊结构。
第四步:测试和优化最后,我们需要对实现的排序算法进行测试和优化。
排序的实验报告范文数据结构实验报告实验名称:实验四排序学生姓名:班级:班内序号:学号:日期:2022年12月21日实验要求题目2使用链表实现下面各种排序算法,并进行比较。
排序算法:1、插入排序2、冒泡排序3、快速排序4、简单选择排序5、其他要求:1、测试数据分成三类:正序、逆序、随机数据。
2、对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数(其中关键字交换计为3次移动)。
3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)。
4、对2和3的结果进行分析,验证上述各种算法的时间复杂度。
编写测试main()函数测试线性表的正确性。
2、程序分析2.1存储结构说明:本程序排序序列的存储由链表来完成。
其存储结构如下图所示。
(1)单链表存储结构:结点地址:1000HA[2]结点地址:1000H1080H……头指针地址:1020HA[0]头指针地址:1020H10C0H……地址:1080HA[3]地址:1080HNULL……地址:10C0HA[1]地址:10C0H1000H……(2)结点结构tructNode{intdata;Node某ne某t;};示意图:intdataNode某ne某tintdataNode某ne某t2.2关键算法分析一:关键算法(一)直接插入排序voidLinkSort::InertSort()直接插入排序是插入排序中最简单的排序方法,其基本思想是:依次将待排序序列中的每一个记录插入到一个已排好的序列中,直到全部记录都排好序。
(1)算法自然语言1.将整个待排序的记录序列划分成有序区和无序区,初始时有序区为待排序记录序列中的第一个记录,无序区包括所有剩余待排序的记录;2.将无须去的第一个记录插入到有序区的合适位置中,从而使无序区减少一个记录,有序区增加一个记录;3.重复执行2,直到无序区中没有记录为止。
(2)源代码voidLinkSort::InertSort()//从第二个元素开始,寻找前面那个比它大的{Node某P=front->ne某t;//要插入的节点的前驱while(P->ne某t){Node某S=front;//用来比较的节点的前驱while(1){if(P->ne某t->data<S->ne某t->data)//P的后继比S的后继小则插入{inert(P,S);break;}S=S->ne某t;if(S==P)//若一趟比较结束,且不需要插入{P=P->ne某t;break;}}}}(3)时间和空间复杂度最好情况下,待排序序列为正序,时间复杂度为O(n)。
写出以单链表为存储结构的一组数据的简单选择排序算法。
以下是单链表存储结构的简单选择排序算法的实现:
```python
def selection_sort(link_list):
n = len(link_list)
for i in range(n):
min_idx = i
for j in range(i+1, n):
if link_list[j] < link_list[min_idx]:
min_idx = j
link_list[i], link_list[min_idx] = link_list[min_idx], link_list[i]
return link_list
```
算法的基本思路是,遍历待排序的链表,找到未排序部分中的最小值,然后将该值与链表的第一个元素交换位置,然后再遍历剩余的元素,继续按照此方法进行排序,直到整个链表都被排序。
在上面的实现中,我们通过 `min_idx` 变量来保存当前未排序部分中的最小值的索引。
在第一次遍历时,min_idx 等于 i,因为在未排序部分中,第一个元素通常是最小的。
在后续的遍历中,我们不断地寻找未排序部分中的最小值,并将其与链表的第一个元素交换位置,最后返回排好序的链表。
设计两个有序单链表的合并排序算法有序单链表的合并排序,是一种高效的排序算法,可以在较短的时间内对大量数据进行排序。
这种排序算法的核心在于将两个有序的单链表合并成一个有序的单链表,然后再对整个链表进行排序。
合并排序算法的基本原理是分治法。
将需要排序的数组不断地分解成两个子数组,直到每个子数组只包含一个元素为止。
然后再将这些子数组两两合并,直到整个数组被合并成一个有序的数组为止。
这里介绍两个有序单链表的合并排序算法,它们分别是迭代算法和递归算法。
1. 迭代算法迭代算法是一种通用的算法,它的思路是利用循环结构来重复执行一段相同或相似的代码,从而解决一类问题。
对于有序单链表的合并排序,迭代算法的基本思路是将两个有序单链表的元素依次比较,然后将较小的元素加入到新的链表中,直到两个链表中的元素全部被加入到新链表中为止。
以下是迭代算法的具体实现过程:```// 合并两个有序单链表Node* mergeList(Node* head1, Node* head2) { // 新建一个头结点Node* dummy = new Node(-1);// 定义两个指针,分别指向两个链表的头结点 Node* p = head1;Node* q = head2;// 定义一个指针,指向新链表的最后一个节点 Node* curr = dummy;// 循环比较两个链表中的元素while (p != nullptr && q != nullptr) {if (p->val <= q->val) {curr->next = p;p = p->next;} else {curr->next = q;q = q->next;}curr = curr->next;}// 将剩余的元素加入到新链表中curr->next = p != nullptr ? p : q;// 返回新链表的头结点return dummy->next;}// 归并排序Node* mergeSort(Node* head) {if (head == nullptr || head->next == nullptr) {return head;}// 定义两个指针,一个快指针每次走两步,一个慢指针每次走一步 Node* slow = head;Node* fast = head->next;while (fast != nullptr && fast->next != nullptr) {slow = slow->next;fast = fast->next->next;}// 将链表分成两部分Node* head1 = head;Node* head2 = slow->next;slow->next = nullptr;// 分别对两部分链表进行归并排序head1 = mergeSort(head1);head2 = mergeSort(head2);// 合并两个有序单链表return mergeList(head1, head2);}```2. 递归算法递归算法的思想是将一个大问题分解成若干个小问题,然后逐个解决这些小问题,最终得到大问题的解决方案。
c语言链表排序算法在C语言中,链表的排序可以使用多种算法,如插入排序、归并排序、快速排序等。
以下是一个简单的插入排序算法的示例,用于对链表进行排序:C:#include<stdio.h>#include<stdlib.h>struct Node {int data;struct Node* next;};void insert(struct Node** head, int data) {struct Node* newNode= (struct Node*)malloc(sizeof(struct Node));newNode->data = data;newNode->next = NULL;if (*head == NULL) {*head = newNode;return;}struct Node* current = *head;while (current->next != NULL) {current = current->next;}current->next = newNode;}void sortList(struct Node** head) { struct Node* current = *head;while (current != NULL) {struct Node* next = current->next; while (next != NULL) {if (current->data > next->data) { int temp = current->data;current->data = next->data;next->data = temp;}next = next->next;}current = current->next;}}void printList(struct Node* head) { while (head != NULL) {printf("%d ", head->data);head = head->next;}}int main() {struct Node* head = NULL;insert(&head, 5);insert(&head, 2);insert(&head, 4);insert(&head, 1);insert(&head, 3);printf("Before sorting: ");printList(head);sortList(&head);printf("\nAfter sorting: ");printList(head);return0;}这个程序定义了一个链表节点结构体Node,其中包含一个整型数据data 和一个指向下一个节点的指针next。
数据结构实验报告实验名称:实验三排序学生姓名:班级:班内序号:15学号:日期:2016.12.191.实验要求题目2使用链表实现下面各种排序算法,并进行比较。
排序算法:1、插入排序2、冒泡排序3、快速排序4、简单选择排序5、其他要求:1、测试数据分成三类:正序、逆序、随机数据2、对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数(其中关键字交换计为3次移动)。
3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)4、对2和3的结果进行分析,验证上述各种算法的时间复杂度编写测试main()函数测试线性表的正确性2. 程序分析2.1 存储结构我使用了线性表的链式存储结构,通过建立双向循环链表进行顺序存取。
每个节点分为data、next、previor。
data域称为数据域,数据通过node结构存储待排序的信息;next为指针域,用来储存直接后继的地址;prior为指针域,用来储存直接前继的地址;struct Node{int data;struct Node*next;struct Node*previor;};2.2 程序流程(或程序结构、或类关系图等表明程序构成的内容,一般为流{private:Node* partion(Node*first,Node*end); //快速排序一趟public:Node*front;int comparision; //比较次数int movement; //移动次数LinkList() //无参构造{front = new Node;front->next = NULL;front->previor = NULL;comparision = movement = 0;}LinkList(int a[],int n); //构造函数:建立双向链表void insertsort(); //插入排序void bubblesort(); //冒泡排序void Qsort(Node*x,Node*y); //快速排序void selectsort(); //简单选择排序void show(); //显示排序结果~LinkList(); //析构函数};2.3 关键算法分析构造函数:通过使用头插法建立双向链表,其关键是多设一个指针变量用于储存上一个末节点的地址,这样才能使节点指向其上一个节点。
在这次排序实验中,使用双向循环链表更方便进行遍历操作。
LinkList::LinkList(int a[],int n){front = new Node;front->next = NULL;front->previor = NULL;comparision = movement = 0;Node*x = new Node;Node*s = new Node;s->data = a[n - 1];s->next = front;s->previor = front;front->next = s;front->previor = s;x = s;for (int i = n - 2; i >= 0; i--){Node*s = new Node;s->data = a[i];s->next = front->next;s->previor = front;front->next = s;x->previor = s;x = s;}}插入排序函数:将front头节点当作哨兵。
从第二个有效节点开始进行插入,进行边查找,边后移的操作。
void LinkList::insertsort(){Node*p = front->next;Node*s = p->next;while (s!=front){if (s->data < p->data){comparision++;front->data = s->data;movement++;Node*x = p;Node*y = s;while (front->data < x->data){comparision++;y->data = x->data;movement++;x = x->previor;y = y->previor;}y->data = front->data;movement++;}comparision++;p = p->next;s = s->next;}}冒泡排序函数:每一次内循环边比较边交换,将无序区中最大的数放入有序区中,并记录无序元素的范围。
当无序元素指向front时即整体排序完成。
void LinkList::bubblesort(){Node*s = front->previor; //初始化无序元素位置while (s != front){Node*p = s; //本次无序元素位置s = front;Node*x = front->next;Node*y = x->next;while (x != p){if (x->data > y->data){comparision++;front->data = x->data;x->data = y->data;y->data = front->data;movement = movement + 3;s = x; //更新无序元素位置}comparision++;x = x->next;y = y->next;}}}快速排序函数:快速排序函数是个递归调用函数,关键在一次快速排序函数的编写。
选择第一个元素作为分区的轴值,将待排序元素分成左右两个区域,左区的元素都比轴值小,右边的都更大。
然后反复进行此操作,即可完成排序。
而结束递归的关键便是左右分界节点有了直接前后继关系的时候。
void LinkList::Qsort(Node*x,Node*y){if (x->previor != y){Node*pivot = partion(x, y);Qsort(x, pivot->previor);Qsort(pivot->next, y);}}Node* LinkList::partion(Node*first, Node*end){int basic = first->data;while (first != end){while ((first != end) && (end->data >= basic)){end = end->previor;comparision++;}comparision++;first->data = end->data;movement++;while ((first != end) && (first->data <= basic)){first = first->next;comparision++;}comparision++;end->data = first->data;movement++;}first->data = basic;movement++;return first;}简单选择排序函数:是将待排序中最小的元素放置序列最前面,其关键是先通过循环比较确定最小元素的位置,再进行数据交换,从而大大减少了元素交换的次数。
void LinkList::selectsort(){Node*s = front->next;while (s != front->previor){Node*p = s->next;Node*record = s;while (p != front){Node*x = record;if (p->data < x->data){comparision++;record = p;}comparision++;p = p->next;}if (record != s){int a = record->data;record->data = s->data;s->data = a;movement = movement + 3;}s = s->next;}}3.程序运行结果分析4.总结本次实验进行了使用链表存储结构实现插入排序、冒泡排序、快速排序、简单选择排序的编程。
这使我对不同的排序方法有了更加深刻的理解和认识。
从中也体会到不同的排序方式所耗费的时间复杂度实在是大相径庭,这警示我们,编写一个时间复杂度小的排序函数在进行排序操作时,起着至关重要的作用。
完整代码如下:#include<iostream>#include<iomanip>using namespace std;struct Node{int data;struct Node*next;struct Node*previor;};class LinkList{private:Node* partion(Node*first,Node*end); //快速排序一趟public:Node*front;int comparision; //比较次数int movement; //移动次数LinkList() //无参构造{front = new Node;front->next = NULL;front->previor = NULL;comparision = movement = 0;}LinkList(int a[],int n); //构造函数:建立双向链表void insertsort(); //插入排序void bubblesort(); //冒泡排序void Qsort(Node*x,Node*y); //快速排序void selectsort(); //简单选择排序void show(); //显示排序结果~LinkList(); //析构函数};LinkList::LinkList(int a[],int n){front = new Node;front->next = NULL;front->previor = NULL;comparision = movement = 0;Node*x = new Node;Node*s = new Node;s->data = a[n - 1];s->next = front;s->previor = front;front->next = s;front->previor = s;x = s;for (int i = n - 2; i >= 0; i--){Node*s = new Node;s->data = a[i];s->next = front->next;s->previor = front;front->next = s;x->previor = s;x = s;}}Node* LinkList::partion(Node*first, Node*end){int basic = first->data;while (first != end){while ((first != end) && (end->data >= basic)){end = end->previor;comparision++;}comparision++;first->data = end->data;movement++;while ((first != end) && (first->data <= basic)){first = first->next;comparision++;}comparision++;end->data = first->data;movement++;}first->data = basic;movement++;return first;}void LinkList::insertsort(){Node*p = front->next;Node*s = p->next;while (s!=front){if (s->data < p->data){comparision++;front->data = s->data;movement++;Node*x = p;Node*y = s;while (front->data < x->data){comparision++;y->data = x->data;movement++;x = x->previor;y = y->previor;}y->data = front->data;movement++;}comparision++;p = p->next;s = s->next;}}void LinkList::bubblesort(){Node*s = front->previor; //初始化无序元素位置while (s != front){Node*p = s; //本次无序元素位置s = front;Node*x = front->next;Node*y = x->next;while (x != p){if (x->data > y->data){comparision++;front->data = x->data;x->data = y->data;y->data = front->data;movement = movement + 3;s = x; //更新无序元素位置}comparision++;x = x->next;y = y->next;}}}void LinkList::Qsort(Node*x,Node*y){if (x->previor != y){Node*pivot = partion(x, y);Qsort(x, pivot->previor);Qsort(pivot->next, y);}}void LinkList::selectsort(){Node*s = front->next;while (s != front->previor){Node*p = s->next;Node*record = s;while (p != front){Node*x = record;if (p->data < x->data){comparision++;record = p;}comparision++;p = p->next;}if (record != s){int a = record->data;record->data = s->data;s->data = a;movement = movement + 3;}s = s->next;}}void LinkList::show(){Node*x = new Node;x = front->next;while (x != front){cout << x->data << setw(4);x = x->next;}cout << endl << "比较次数:" << comparision << endl;cout << "移动次数:" << movement << endl;cout << endl;}LinkList:: ~LinkList(){Node*p = front;while (p!=front){Node*a = p;p = p->next;delete a;}delete p;}void showmenu();int main(){showmenu();cin.get();cin.get();return 0;}void showmenu(){int jay1[7] = { 2,6,7,9,15,24,29 };int jay2[7] = { 54,40,38,37,29,24,12 };int jay3[7] = { 16,45,81,1,4,69,100 };LinkList zzj1(jay1, 7);LinkList zzj2(jay2, 7);LinkList zzj3(jay3, 7);cout << "正序数据:"; zzj1.show();cout << "逆序数据:"; zzj2.show();cout << "乱序数据:"; zzj3.show();int choice;cout << "请选择所要操作的内容:\n""1.插入排序 2.冒泡排序\n""3.快速排序 4.简单选择排序\n""5.退出\n";cin >> choice;int count = 0;Node*x, *y, *z;while (choice != 5){switch (choice){case 1:if (count != 0){x = zzj1.front->next;y = zzj2.front->next;z = zzj3.front->next;for (int i = 0; i < 7; i++){x->data = jay1[i];y->data = jay2[i];z->data = jay3[i];x = x->next;y = y->next;z = z->next;}parision = zzj1.movement = 0;parision = zzj2.movement = 0;parision = zzj3.movement = 0;}cout << "插入排序:\n";zzj1.insertsort();zzj2.insertsort();zzj3.insertsort();zzj1.show();zzj2.show();zzj3.show();count = 1;break;case 2:if (count != 0){x = zzj1.front->next;y = zzj2.front->next;z = zzj3.front->next;for (int i = 0; i < 7; i++){x->data = jay1[i];y->data = jay2[i];z->data = jay3[i];x = x->next;y = y->next;z = z->next;}parision = zzj1.movement = 0;parision = zzj2.movement = 0;parision = zzj3.movement = 0;}zzj1.bubblesort();zzj2.bubblesort();zzj3.bubblesort();cout << "冒泡排序:\n";zzj1.show();zzj2.show();zzj3.show();count = 1;break;case 3:if (count != 0){x = zzj1.front->next;y = zzj2.front->next;z = zzj3.front->next;for (int i = 0; i < 7; i++){x->data = jay1[i];y->data = jay2[i];z->data = jay3[i];x = x->next;y = y->next;z = z->next;}parision = zzj1.movement = 0;parision = zzj2.movement = 0;parision = zzj3.movement = 0;}x = zzj1.front;y = zzj2.front;z = zzj3.front;zzj1.Qsort(x->next, x->previor);zzj2.Qsort(y->next, y->previor);zzj3.Qsort(z->next, z->previor);cout << "快速排序:\n";zzj1.show();zzj2.show();zzj3.show();count = 1;break;case 4:if (count != 0){x = zzj1.front->next;y = zzj2.front->next;z = zzj3.front->next;for (int i = 0; i < 7; i++){x->data = jay1[i];y->data = jay2[i];z->data = jay3[i];x = x->next;y = y->next;z = z->next;}parision = zzj1.movement = 0;parision = zzj2.movement = 0;parision = zzj3.movement = 0;}zzj1.selectsort();zzj2.selectsort();zzj3.selectsort();cout << "简单选择排序:\n";zzj1.show();zzj2.show();zzj3.show();count = 1;break;default:cout << "这不是一个选项。