一、插入排序 Insertion sort
插入排序很像玩扑克牌中整理手牌的过程,从第二个数开始依次比较其与前面所用数据的大小,直到找到其需要在的位置。当从第二个数据遍历到最后一个数据之后就完成了整个数组的排序。
void InsertionSort(int arr[], int n)
{
for(int i = 0; i<n ; i++)
{
int temp = arr[i];
int j = i-1;
//依次向前遍历找到比temp小的第一个数
for (j = i-1; temp < arr[j] && j >= 0; j--)
{
//将比temp大的数依次向后移动一位
arr[j+1] = arr[j];
}
//将temp插入到其正确的位置中
arr[j+1] = temp;
}
}
二、链表的插入排序
对于单向链表只能从前向后遍历,故从头节点遍历寻找未排好序的节点,如果是数组的话便只需向前遍历找到其正确的位置便可,但由于单向链表无法向前遍历只能重新从头遍历直到找到其正确位置。
同时为防止下次排序时需要从头遍历寻找未排好序的节点,可用precurrent指针储存已排好序的最后一节点,用temp指针储存需要移动的节点。
并且未防止节点需要插入头节点之前而产生边界问题进行讨论,则可以创建一个新的节点作为一个虚假的头节点并用prehead指向此节点。这样便将插入头节点之前变成了在两节点之间插入节点。
第一遍代码:但有错误,需要更改。
Node* InsertionSort(Node *head)
{
//如果链表长度为0或1,不需要排序。
if(head == NULL || head->nextptr == NULL )
{
return head;
}
//创建一个移动的指针遍历链表
Node *current = head ;
//创建一个虚假的头节点,将问题归一化处理
Node *fakehead = new Node ;
fakehead->Number = "0";
fakehead->nextptr = head ;
//创建一个节点来储存current前一节点
Node *precurrent = fakehead ;
//创建一个临时指针指向未排好序的节点
Node *temp = NULL ;
//从头节点遍历链表寻找到第一个未排好序的节点
while (current->nextptr != NULL)
{
//时刻保持precurrent指向current指向的前一个节点
if(precurrent->Number <= current->Number)
{
precurrent = current ;
current = current->nextptr ;
}
else
{
temp = precurrent ;//错误,储存了要移动节点的前一节点
//从链表中移出temp指针指向的节点
precurrent->nextptr = current->nextptr ;
//使用current指针遍历已排序的链表寻找temp指针指向节点的正确位置
current = fakehead ;
/*将temp节点中的数据与current指向节点的下一个节点比较,
保证最后current指向的节点为temp节点所需插入位置的前一个*/
while (temp->Number <= current->nextptr->Number)//错误
//排列的升降序未注意
{
current = current->nextptr ;
}
//将temp指向的节点插入current指向节点之后
temp->nextptr = current->nextptr ;
current->nextptr = temp ;
//将current指针重新指向precurrent指针指向的节点的下一个节点
current = precurrent->nextptr ;
}
}
head = fakehead->nextptr ;
delete fakehead ;
return head;
}
Leetcode的代码题解:
ListNode* insertionSortList(ListNode* head) { if (head == nullptr) { return head; } ListNode* dummyHead = new ListNode(0); dummyHead->next = head; ListNode* lastSorted = head; ListNode* curr = head->next; while (curr != nullptr) { if (lastSorted->val <= curr->val) { lastSorted = lastSorted->next; } else { ListNode *prev = dummyHead; while (prev->next->val <= curr->val) { prev = prev->next; } lastSorted->next = curr->next; curr->next = prev->next; prev->next = curr; } curr = lastSorted->next; } return dummyHead->next; }
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/insertion-sort-list/solution/dui-lian-biao-jin-xing-cha-ru-pai-xu-by-leetcode-s/
来源:力扣(LeetCode)
还在改进中…………敬请期待
改进后:
Node* InsertionSort(Node *head)
{
//如果链表长度为0或1,不需要排序。
if(head == NULL || head->nextptr == NULL )
{
return head;
}
//创建一个移动的指针遍历链表
Node *current = head ;
//创建一个虚假的头节点,将问题归一化处理
Node *fakehead = new Node ;
fakehead->Number = "0";
fakehead->nextptr = head ;
//创建一个节点来储存current前一节点
Node *precurrent = fakehead ;
//创建一个临时指针指向未排好序的节点
Node *temp = NULL ;
//从头节点遍历链表寻找到第一个未排好序的节点
while (current->nextptr != NULL)
{
//时刻保持precurrent指向current指向的前一个节点
if(precurrent->Number <= current->Number)
{
precurrent = current ;
current = current->nextptr ;
}
else
{
//不应是temp = precurrent 否则将储存要移动节点的前一节点
temp = current ;
//从链表中移出temp指针指向的节点
precurrent->nextptr = current->nextptr ;
//暂时使用current指针遍历已排好序的链表寻找temp指针指向节点应该在的位置
current = fakehead ;
/*将temp节点中的数据与current指向节点的下一个节点比较,
保证最后current指向的节点为temp节点所需插入位置的前一个*/
while (temp->Number >= current->nextptr->Number)
/*temp->Number <= current->nextptr->Number错误
因为需要升序排列,此为降序*/
{
current = current->nextptr ;
}
//将temp指向的节点插入current指向节点之后
temp->nextptr = current->nextptr ;
current->nextptr = temp ;
//将current指针重新指向precurrent指针指向的节点的下一个节点
current = precurrent->nextptr ;
}
}
head = fakehead->nextptr ;
delete fakehead ;
return head;
}
注:需时刻注意指针指向的位置!!!应该画个图分析!!!
全部代码如下:
#include <iostream>
using namespace std;
struct Node
{
string Name;
long long Number;
string Sex;
int age;
Node* nextptr;
};
void BuildList(Node *head, int n);
void PrintList(Node *print);
void DeleteList(Node *current);
Node* InsertionSort(Node *current);
int main()
{
Node *head = new Node;
head->nextptr = NULL;
BuildList(head, 10);
cout << "Before ordering(id|age|name|sex)" << endl ;
PrintList(head);
head = InsertionSort(head);
cout << "After ordering(id|age|name|sex)" << endl ;
PrintList(head);
DeleteList(head);
return 0;
}
void BuildList(Node *head, int n)
{
Node *current = head;
for(int i=0; i<n; i++)
{
cin >> current->Name >> current->Number
>> current->Sex >> current->age;
//创建一个新节点
current->nextptr = new Node;
current = current->nextptr;
current->nextptr = NULL;
}
}
void PrintList(Node *print)
{
while(print->nextptr != NULL)
{
cout << "(" << print->Number << "|" << print->age
<< "|" << print->Name << "|" << print->Sex << ")" << endl;
print = print->nextptr ;
}
}
void DeleteList(Node *current)
{
Node *temp = NULL;
//遍历链表删除节点
while(current != NULL)
{
temp = current;
current = current->nextptr;
delete temp;
}
}
Node* InsertionSort(Node *head)
{
//如果链表长度为0或1,不需要排序。
if(head == NULL || head->nextptr == NULL )
{
return head;
}
//创建一个移动的指针遍历链表
Node *current = head ;
//创建一个虚假的头节点,将问题归一化处理
Node *fakehead = new Node ;
fakehead->Number = 0;
fakehead->nextptr = head ;
//创建一个节点来储存current前一节点
Node *precurrent = fakehead ;
//创建一个临时指针指向未排好序的节点
Node *temp = NULL ;
//从头节点遍历链表寻找到第一个未排好序的节点
while (current->nextptr != NULL)
{
//时刻保持precurrent指向current指向的前一个节点
if(precurrent->Number <= current->Number)
{
precurrent = current ;
current = current->nextptr ;
}
else
{
//不应是temp = precurrent 否则将储存要移动节点的前一节点
temp = current ;
//从链表中移出temp指针指向的节点
precurrent->nextptr = current->nextptr ;
//暂时使用current指针遍历已排好序的链表寻找temp指针指向节点应该在的位置
current = fakehead ;
/*将temp节点中的数据与current指向节点的下一个节点比较,
保证最后current指向的节点为temp节点所需插入位置的前一个*/
while (temp->Number >= current->nextptr->Number)
/*temp->Number <= current->nextptr->Number错误
因为需要升序排列,此为降序*/
{
current = current->nextptr ;
}
//将temp指向的节点插入current指向节点之后
temp->nextptr = current->nextptr ;
current->nextptr = temp ;
//将current指针重新指向precurrent指针指向的节点的下一个节点
current = precurrent->nextptr ;
}
}
head = fakehead->nextptr ;
delete fakehead ;
return head;
}