Using C language to sort students' grades (insertion sort algorithm)

1. Sorting algorithm

1. Sort

Starting today we will start learning sorting algorithms!

Sorting is the process of rearranging the elements in the table so that the elements in the table meet the order of keywords. For the convenience of searching, it is usually hoped that the tables in the computer are ordered by keywords.

2. Stability

In addition to the time complexity and space complexity we have learned before to judge whether an algorithm is good or bad, we introduce a new judgment standard in the sorting algorithm - stability.

algorithm stability . If there are two elements R in the list to be sorted; and R, the corresponding keywords are the same, that is, key i = key j , and before sorting, R i is in front of R j , if a sorting algorithm is used to sort, R i Still in front of R j , the sorting algorithm is said to be stable, otherwise the sorting algorithm is said to be unstable. It should be noted that whether an algorithm is stable does not measure the pros and cons of an algorithm, it mainly describes the nature of the algorithm. If the keywords in the list to be sorted are not allowed to be repeated, the sorting result is unique, and it doesn't matter whether the sorting algorithm is stable or not.

3. Algorithm classification

insert image description here

It should be noted here that the topological sorting in our last blog in the application of graphs is not a sorting algorithm in our strict sense.

2. Direct insertion sort

1. Operation steps

To insert an element L(i) into the ordered subsequence [1...i-1], the following operations need to be performed (to avoid confusion, L[ ] is used below to represent a list, and L() is used to represent an element) :

  • 1) Find out the insertion position k of L(i) in L[...i-1].
  • 2) All the elements in L[.1i-1] are shifted backward by one position.
  • 3) Copy L(i) to L(k).

In order to sort L1...n], L(2) ~L (n) can be sequentially inserted into the previously sorted subsequence, and the initial L[1] can be regarded as a sorted subsequence. An ordered table can be obtained by performing the above operations n-1 times. Insertion sorting usually adopts in-place sorting (space complexity is 0(1)) in implementation, so in the process of comparison from back to front, it is necessary to repeatedly move the sorted elements backward gradually to provide insertion space for new elements .

2. Demonstration example

Assume that the initial sequence is 49, 38, 65, 97, 76, 13, 27, 49. Initially, 49 can be regarded as a sorted subsequence. The process of direct insertion sorting according to the above algorithm is shown in the figure, with brackets Inside is the sorted subsequence.

insert image description here

3. Performance analysis

Space Efficiency: Only a constant number of auxiliary units are used, resulting in a space complexity of 0(1).

Time efficiency: During the sorting process, the operation of inserting elements one by one into the ordered sublist is performed n-1 times, and each operation is divided into comparison keywords and moving elements, and the number of comparisons and moving times depends on the number of operations to be sorted The initial state of the table. In the best case, the elements in the table are already in order. At this time, each time an element is inserted, it only needs to be compared once without moving the element, so the time complexity is 0(n). In the worst case, the order of the elements in the table is just opposite to the order of the elements in the sorting result (reverse order), the total number of comparisons reaches the maximum, the total number of moves also reaches the maximum, and the total time complexity is 0(2). On average, considering that the elements in the list to be sorted are random, the average of the above-mentioned best and worst cases can be taken as the time complexity in the average case. The total number of comparisons and the total number of moves are about n 2/4 .

4. Code implementation

//直接插入排序
void InsertSort1(SqList &L){
    
    
	Elemtype temp;
	int i,j;
	for(i=1;i<L.length;i++){
    
    
		if(L.data[i].grade<L.data[i-1].grade){
    
    
			temp=L.data[i];
			for(j=i-1;j>=0 && temp.grade<L.data[j].grade;--j)    //从后往前查找待插入的位置
				L.data[j+1]=L.data[j];                 //向后挪位
			L.data[j+1]=temp;
		}
	}
}

3. Half insertion sort

1. Operation steps

Here is a brief description, please refer to the blog linear table search algorithm for binary search for details

From the direct insertion sorting algorithm, it is not difficult to see that two tasks are performed in each insertion process: ①Find out the position where the element to be inserted should be inserted from the previous ordered sub-list; ②Make room for the insertion position , copy the element to be inserted to the insertion position in the table. Note that in this algorithm, elements are always moved while comparing. Next, the comparison and moving operations are separated, that is, first find the position to be inserted in half, and then uniformly move all elements after the position to be inserted. When the sorted table is a sequential table, the direct insertion sorting algorithm can be improved as follows: since it is a linear table stored in sequence, the binary search can be used to find the ordered sub-list. Once the position to be inserted is determined, the elements can be moved backward uniformly.

2. Performance analysis

From the above algorithm, it is not difficult to see that the half insertion sort only reduces the number of comparison elements, which is about O(nlog2n), and the number of comparisons has nothing to do with the initial state of the list to be sorted, but only depends on the number n of elements in the table; and The number of shifts of elements does not change, it depends on the initial state of the list to be sorted. Therefore, the time complexity of half-insertion sorting is still O(n2), but for sorted tables with a small amount of data, half-insertion sorting can often show very good performance. Binary insertion sort is a stable sorting method.

3. Code implementation

//折半插入排序
void InsertSort2(SqList &L){
    
    
	Elemtype temp;
	int i, j, low, high, mid;
	for(i=1; i<L.length; i++){
    
    
		temp = L.data[i];
		low = 0; high = i-1;
		while(low <= high){
    
     //折半查找
			mid = (low + high) / 2; //取中间点
			if(L.data[mid].grade > temp.grade)
				high = mid - 1;
			else
				low = mid + 1;
		}
		for(j=i-1; j>=high+1; --j){
    
    
			L.data[j+1] = L.data[j];
		}
		L.data[high+1] = temp;
	}
}

Four. Hill sort

1. Sorting process

The process of Hill sorting is as follows: first take a step size d smaller than n, divide all the records in the table into d groups, put all the records whose distance is a multiple of d1 into the same group, and perform direct insertion sorting in each group; then take The second step size d2<d, repeat the above process until the obtained d t = 1, that is, all records have been placed in the same group, and then perform direct insertion sorting, because at this time there is already a good local sequence, so the final result can be obtained quickly. So far, a best incremental sequence has not been obtained.

The person who proposed this algorithm advocated the use of d=n/2

2. Demonstration example

insert image description here

3. Performance analysis

Space Efficiency: Only a constant number of auxiliary units are used, resulting in a space complexity of 0(1).

Time efficiency: Since the time complexity of Hill sorting depends on the function of the incremental sequence, which involves an unsolved problem in mathematics, it is difficult to analyze its time complexity. When n is in a certain range, the time complexity of Hill sorting is about 0(n l.3 ). In the worst case, the time complexity of Hill sorting is 0(n 2 ).

Stability: When the records of the same keyword are divided into different sub-tables, the relative order between them may be changed, so Hill sorting is an unstable sorting method.

4. Code implementation

//希尔排序
void ShellSort(SqList &L){
    
    
	int dk,i,j;
	Elemtype temp;
	for(dk=L.length/2;dk>=1;dk=dk/2){
    
    
		for(i=dk;i<L.length;++i){
    
    
			if(L.data[i].grade<L.data[i-dk].grade){
    
    
				temp=L.data[i];
				for(j=i-dk;j>=0 && temp.grade<L.data[j].grade;j-=dk)
					L.data[j+dk]=L.data[j];
				L.data[j+dk];
			}
		}
	}
}

5. C language demo code

/*我们今天的主角插入排序是基于查找算法来的,所以我们还是利用线性表来进行模拟*/

/*为了便于我们后面演示希尔排序,所以我们采用顺序存储结构*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MaxSize 50                //这里只是演示,我们假设这里最多存五十个学生信息

//定义学生结构
typedef struct {
    
    
	char name[200];              //姓名
	int  grade;               //分数,这个是排序关键字
} Elemtype;

//声明使用顺序表
typedef struct {
    
    
	/*这里给数据分配内存,可以有静态和动态两种方式,这里采用动态分配*/
	Elemtype  *data;            //存放线性表中的元素是Elemtype所指代的学生结构体
	int length;                 //存放线性表的长度
} SqList;						//给这个顺序表起个名字,接下来给这个结构体定义方法

//初始化线性表
void InitList(SqList &L){
    
    
	/*动态分配内存的初始化*/
	L.data = (Elemtype*)malloc(MaxSize * sizeof(Elemtype));  //为顺序表分配空间
	L.length = 0;                                            //初始化长度为0
}

//求表长函数
int Length(SqList &L){
    
    
	return L.length;
}

//求某个数据元素值
bool GetElem(SqList &L, int i, Elemtype &e) {
    
    
	if (i < 1 || i > L.length)
		return false;         //参数i错误时,返回false
	e = L.data[i - 1];      //取元素值
	return true;
}

//输出线性表
void DispList(SqList &L) {
    
    
	if (L.length == 0)
		printf("线性表为空");
	//扫描顺序表,输出各元素
	for (int i = 0; i < L.length; i++) {
    
    
		printf("%s        %d", L.data[i].name,  L.data[i].grade);
		printf("\n");
	}
	printf("\n");
}

//插入数据元素
bool ListInsert(SqList &L, int i, Elemtype e) {
    
    
	/*在顺序表L的第i个位置上插入新元素e*/
	int j;
	//参数i不正确时,返回false
	if (i < 1 || i > L.length + 1 || L.length == MaxSize)
		return false;
	i--;                //将顺序表逻辑序号转化为物理序号
	//参数i正确时,将data[i]及后面的元素后移一个位置
	for (j = L.length; j > i; j--) {
    
    
		L.data[j] = L.data[j - 1];
	}
	L.data[i] = e;      //插入元素e
	L.length++;         //顺序表长度加1
	return true;
	/*平均时间复杂度为O(n)*/
}

//直接插入排序
void InsertSort1(SqList &L){
    
    
	Elemtype temp;
	int i,j;
	for(i=1;i<L.length;i++){
    
    
		if(L.data[i].grade<L.data[i-1].grade){
    
    
			temp=L.data[i];
			for(j=i-1;j>=0 && temp.grade<L.data[j].grade;--j)    //从后往前查找待插入的位置
				L.data[j+1]=L.data[j];                 //向后挪位
			L.data[j+1]=temp;
		}
	}
}
/*还记得我们之前学的查找算法吗,其实就是线性查找和折半查找到需要插入元素的位置*/

//折半插入排序
void InsertSort2(SqList &L){
    
    
	Elemtype temp;
	int i, j, low, high, mid;
	for(i=1; i<L.length; i++){
    
    
		temp = L.data[i];
		low = 0; high = i-1;
		while(low <= high){
    
     //折半查找
			mid = (low + high) / 2; //取中间点
			if(L.data[mid].grade > temp.grade)
				high = mid - 1;
			else
				low = mid + 1;
		}
		for(j=i-1; j>=high+1; --j){
    
    
			L.data[j+1] = L.data[j];
		}
		L.data[high+1] = temp;
	}
}

//希尔排序
void ShellSort(SqList &L){
    
    
	int dk,i,j;
	Elemtype temp;
	for(dk=L.length/2;dk>=1;dk=dk/2){
    
    
		for(i=dk;i<L.length;++i){
    
    
			if(L.data[i].grade<L.data[i-dk].grade){
    
    
				temp=L.data[i];
				for(j=i-dk;j>=0 && temp.grade<L.data[j].grade;j-=dk)
					L.data[j+dk]=L.data[j];
				L.data[j+dk]=temp;
			}
		}
	}
}

int main(){
    
    
	SqList L;
	Elemtype stuents[10]={
    
    {
    
    "张三",649},{
    
    "李四",638},{
    
    "王五",665},{
    
    "赵六",697},{
    
    "冯七",676},
		{
    
    "读者",713},{
    
    "阿强",627},{
    
    "杨曦",649},{
    
    "老六",655},{
    
    "阿黄",604}};
	//这一部分忘了的请回顾我的相关博客
	printf("初始化顺序表并插入开始元素:\n");
	InitList(L);         //这时是一个空表,接下来通过插入元素函数完成初始化
	for (int i = 0; i < 10; i++)
		ListInsert(L, i + 1, stuents[i]);
	DispList(L);
	printf("根据分数进行直接插入排序后:\n");
	InsertSort1(L);
	DispList(L);
	/*
	  printf("根据分数进行折半插入排序后:\n");
	  InsertSort2(L);
	  DispList(L);
	  printf("根据分数进行希尔排序后:\n");
	  ShellSort(L);
	  DispList(L);
	 */
	//请确保这里在进行一次排序后,不要在用其他方法排序,没有意义,可以重新初始化线性表,再换一种方法排序
}





Please note here that for issues related to designing linear tables, please see Sequential Table Algorithm Exercises

6. Running results

1. Direct insertion sort

insert image description here

2. Binary insertion sort

insert image description here

3. Hill sort

insert image description here

Guess you like

Origin blog.csdn.net/weixin_51496226/article/details/131344421