插入排序的算法思想:将待排序元素分为已排序子集和未排序子集,一次从未排序子集中的一个元素插入已排序子集中,使已排序自己仍然有序;重复执行以上过程,指导所有元素都有序为止。
直接插入排序是一种最简单的插入排序算法。
1.数组实现
基本算法思想:把被排序的记录逐个取出,插在适当的位置。即进行第i遍整理时,前i-1个记录A[1],A[2],…,A[i-1],已经排序顺序;取出第i个记录A[i],在整理好的序列中为A[i]找到一个合适的位置j,即A[1],A[2],…,A[j-1]的关键字都小于或等于A[i]的关键字,而A[j],…,A[i-1]中的关键字都大于A[i]的关键字;将从j开始到位置i-1的记录全部后移一步;将原来A[i]中的数据插在A[j];于是,A[1],A[2],…,A[i]仍然是排好顺序的。
例如给定一个含有8个元素的元素,对应的关键字序列为(45,23,56,12,97,76,29,68),将这些元素按照关键字从小到大进行直接插入排序的过程如下图所示。
- 类型定义
#define MaxSize 100
typedef int KeyType;
typedef struct /*数据元素类型定义*/
{
KeyType key;/*关键字*/
}DataType;
typedef struct /*顺序表类型定义*/
{
DataType data[MaxSize];
int length;
}SqList;
- 直接插入排序函数
void InsertSort(SqList *L)
/*直接插入排序*/
{
int i,j;
DataType t;
for(i=1;i<L->length;i++) /*前i个元素已经有序,从第i+1个元素开始与前i个有序的关键字比较*/
{
t=L->data[i+1]; /*取出第i+1个元素,即待排序的元素*/
j=i;
while(j>0&&t.key<L->data[j].key)/*寻找当前元素的合适位置*/
{
L->data[j+1]=L->data[j];
j--;
}
L->data[j+1]=t; /*将当前元素插入合适的位置*/
}
}
- 主程序
#include<stdio.h>
#include<stdlib.h>
void InitSeqList(SqList *L,DataType a[],int n)
/*顺序表的初始化*/
{
int i;
for(i=1;i<=n;i++)
{
L->data[i]=a[i-1];
}
L->length=n;
}
void DispList(SqList L,int n)
/*顺序表的输出*/
{
int i;
for(i=1;i<=n;i++)
printf("%4d",L.data[i].key);
printf("\n");
}
void main()
{
DataType a[]={78,29,45,10,80,21,55,3,60,32};
int delta[]={5,3,1};
int n=10,m=3;
SqList L;
InitSeqList(&L,a,n);
printf("[排序前] ");
DispList(L,n);
InsertSort(&L);
printf("[直接插入排序结果]");
DispList(L,n);
}
2.链表实现
基本算法思想:首先创建一个链表,将待排序元素依次插入链表中。将待排序的链表分为两个部分,即有序序列和待排序序列。初始时,有序序列中没有元素,令L->next=NULL。指针p指向待排序的链表,若有序序列为空,将p指向的第一个结点插入空链表L中。然后将有序链表即L指向的链表的每一个结点与p指向的结点比较,并将结点*p插入L指向的链表的恰当位置。重复执行上述操作,指导待排序链表为空。此时,L就是一个有序链表。
- 链表头文件
void InitList(LinkList *h)
/*单链表的初始化*/
{
if((*h=(LinkList)malloc(sizeof(ListNode)))==NULL) /*为头结点分配一个存储空间*/
exit(-1);
(*h)->next=NULL; /*将单链表的头结点指针域置为空*/
}
int ListEmpty(LinkList h)
/*判断单链表是否为空*/
{
if(h->next==NULL) /*如果链表为空*/
return 1; /*返回1*/
else /*否则*/
return 0; /*返回0*/
}
ListNode *Get(LinkList h,int i)
/*查找单链表中第i个结点。查找成功返回该结点的指针,否则返回NUL*/
{
ListNode *p;
int j;
if(ListEmpty(h)) /*查找第i个元素之前,判断链表是否为空*/
return NULL;
if(i<1) /*判断该序号是否合法*/
return NULL;
j=0;
p=h;
while(p->next!=NULL&&j<i)
{
p=p->next;
j++;
}
if(j==i) /*如果找到第i个结点*/
return p; /*返回指针p*/
else; /*否则*/
return NULL ;/*返回NULL*/
}
ListNode *LocateElem(LinkList h,DataType e)
/*查找线性表中元素值为e的元素,查找成功返回对应元素的结点指针,否则返回NULL */
{
ListNode *p;
p=h->next; /*指针p指向第一个结点*/
while(p)
{
if(p->data!=e) /*如果当前元素值与e不相等*/
p=p->next; /*则继续查找*/
else /*否则*/
break; /*退出循环,停止查找*/
}
return p; /*返回结点的指针*/
}
int LocatePos(LinkList h,DataType e)
/*查找线性表中元素值为e的元素,查找成功返回对应元素的序号,否则返回0*/
{
ListNode *p;
int i;
if(ListEmpty(h)) /*查找第i个元素之前,判断链表是否为空*/
return 0;
p=h->next; /*从第一个结点开始查找*/
i=1;
while(p)
{
if(p->data==e) /*找到与e相等的元素*/
return i; /*返回该序号*/
else /*否则*/
{
p=p->next; /*继续查找*/
i++;
}
}
if(!p) /*如果没有找到与e相等的元素,返回0,表示失败*/
return 0;
}
int InsertList(LinkList h,int i,DataType e)
/*在单链表中第i个位置插入值e的结点。插入成功返回1,失败返回0*/
{
ListNode *p,*pre;
int j;
pre=h; /*指针p指向头结点*/
j=0;
while(pre->next!=NULL&&j<i-1)/*找到第i-1个结点,即第i个结点的前驱结点*/
{
pre=pre->next;
j++;
}
if(j!=i-1) /*如果没找到,说明插入位置错误*/
{
printf("插入位置错");
return 0;
}
/*新生成一个结点,并将e赋值给该结点的数据域*/
if((p=(ListNode*)malloc(sizeof(ListNode)))==NULL)
exit(-1);
p->data=e;
/*插入结点操作*/
p->next=pre->next;
pre->next=p;
return 1;
}
int DeleteList(LinkList h,int i,DataType *e)
/*删除单链表中的第i个位置的结点。删除成功返回1,失败返回0*/
{
ListNode *pre,*p;
int j;
pre=h;
j=0;
while(pre->next!=NULL&&pre->next->next!=NULL&&j<i-1)/*在寻找的过程中确保被删除结点存在*/
{
pre=pre->next;
j++;
}
if(j!=i-1) /*如果没找到要删除的结点位置,说明删除位置错误*/
{
printf("删除位置错误");
return 0;
}
p=pre->next;
*e=p->data;
/*将前驱结点的指针域指向要删除结点的下一个结点,也就是将p指向的结点与单链表断开*/
pre->next=p->next;
free(p); /*释放p指向的结点*/
return 1;
}
int ListLength(LinkList h)
/*求线性表的表长*/
{
ListNode *p;
int count=0;
p=h;
while(p->next!=NULL)
{
p=p->next;
count++;
}
return count;
}
void DestroyList(LinkList h)
/*销毁链表*/
{
ListNode *p,*q;
p=h;
while(p!=NULL)
{
q=p;
p=p->next;
free(q);
}
}
- 类型定义
typedef int DataType; /*元素类型定义为整型*/
typedef struct Node /*单链表类型定义*/
{
DataType data;
struct Node *next;
}ListNode,*LinkList;
- 主程序
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include"LinkList.h"
void CreateList(LinkList L,DataType a[],int n)
/*创建单链表*/
{
int i;
for(i=1;i<=n;i++)
InsertList(L,i,a[i-1]);
}
void InsertSort(LinkList L)
/*链式存储结构下的插入排序*/
{
ListNode *p=L->next,*pre,*q;
L->next=NULL; /*初始时,已排序链表为空*/
while(p!=NULL) /*p是指向待排序的结点*/
{
if(L->next==NULL) /*如果*p是第一个结点,则插入到L,并令已排序的最后一个结点的指针域为空*/
{
L->next=p;
p=p->next;
L->next->next=NULL;
}
else /*p指向待排序的结点,在L指向的已经排好序的链表中查找插入位置*/
{
pre=L;
q=L->next;
while(q!=NULL&&q->data<p->data) /*在q指向的有序表中寻找插入位置*/
{
pre=q;
q=q->next;
}
q=p->next; /*q指向p的下一个结点,保存待排序的指针位置*/
p->next=pre->next; /*将结点*p插入到结点*pre的后面*/
pre->next=p;
p=q; /*p指向下一个待排序的结点*/
}
}
}
void main()
{
LinkList L,p;
int n=8;
DataType a[]={76,55,10,21,65,90,5,38};
InitList(&L);
CreateList(L,a,n);
printf("排序前的元素序列:\n");
for(p=L->next;p!=NULL;p=p->next)
printf("%4d ",p->data);
printf("\n");
InsertSort(L);
printf("排序后的元素序列:\n");
for(p=L->next;p!=NULL;p=p->next)
printf("%4d ",p->data);
printf("\n");
}