Insert sort - linked list sorting algorithm for array and array storage structure

Insert sort idea

When sorting, each element to be sorted is compared with the previous sorted element. If the reverse order occurs, you need to find a suitable position in the sorted element sequence that can keep it in order, find the insertion position, move the sorted sequence back to make space, and then insert the elements to be sorted;

Specific description: for an array A[N], when the ith element (I > = 1) is inserted, the preceding A[0], A[1],..., A[i-1] is the ordered element sequence. When comparing A[i] with A[i-1], if the reverse order occurs, you need to find the insertion position K (where 0 < = k < i-1) in the ordered element sequence. After finding A[k], A[k+1],..., A[i-1] move backward in turn, The position of A[k] is replaced by A[i]

Algorithm steps

Take the insertion sorting process of an ordinary array A[N] from small to large as an example:

Round 1: compare A[0] with A[1]. If there is reverse order, insert it in front of the first element, and move it twice at worst to form a sequence of 2 sorted elements

Round 2: compare A[1] with A[2]. If there is reverse order, find a position to insert in the sequence of 2 ordered elements, and move it for 3 times at the worst to form a sequence of 3 ordered elements

Round 3: compare A[2] with A[3]. Similarly, if there is reverse order, find a position to insert in the sequence of 3 ordered elements, and move it 4 times at the worst to form a sequence of 4 sorted elements

Round N-1: comparing A[N-2] with A[N-1], the worst case is to move N times to form N ordered element sequences, and the sorting is completed

The initial sequence given in the following figure is taken as an example, and the results of each round of sorting are shown in the figure:

Time complexity

Ideally, the initial sorting element sequence has been ordered. Each round only needs to be compared with the last element of the previous ordered element sequence. The total number of comparisons is n-1 and the number of element moves is 0;

Worst case: when the elements to be sorted are in reverse order, the i-th element must be compared with the previous I-Elements, and the data must be moved every comparison

The total number of comparisons is: ∑ i = 1 n − 1 i = 1 + 2 + 3 + . . . + ( n − 1 ) = n ( n − 1 ) 2 ≈ n 2 2 \sum_{i=1}^{n-1} i= 1+2+3+...+(n-1) = \frac{n(n-1)}{2} \approx \frac{n^2}{2} i=1∑n−1​i=1+2+3+...+(n−1)=2n(n−1)​≈2n2​

The total number of moves is: ∑ i = 1 n − 1 ( i + 1 ) = 2 + 3 + . . . + n = ( n − 1 ) ( n + 2 ) 2 ≈ n 2 2 \sum_{i=1}^{n-1} (i+1)= 2+3+...+n = \frac{(n-1)(n+2)}{2} \approx \frac{n^2}{2} i=1∑n−1​(i+1)=2+3+...+n=2(n−1)(n+2)​≈2n2​

Therefore, the total time complexity is o( n 2 n^2 n2), and direct insertion sorting is A stable sorting algorithm, that is, two identical elements A and A 'in the original sequence,

If A is in front of A ', the relative order of A and A' remains unchanged after sorting

Insert sorting source code

#include <stdio.h>
#include <stdlib.h>

//Insert sort: sort from small to large
void insertSort(int arr[], int n) {
  int val;
  for (int i = 1; i < n; i++) {
    //If the latter element is smaller than the previous element
    if (arr[i] < arr[i - 1]) {
      val = arr[i];
      int j = i - 1;
      do {
        arr[j + 1] = arr[j];
        j--;
      } while (j >= 0 && val < arr[j]);
      arr[j + 1] = val;
    }
  }
}
int output(int arr[], int n) {
  for (int i = 0; i < n; i++) {
    printf("%d, ", arr[i]);
  }
  printf("\n");
}

int main() {
  // int arr[] = {6, 3, 7, 4, 2, 8, 5};
  int arr[] = {2, 5, 6, 7, 1, 4, 8, 9};
  // int arr[] = {1};
  int n = sizeof(arr) / sizeof(int);
  insertSort(arr, n);
  output(arr, n);
  return 0;
}

Linked list of array storage structure - insert sort

For the linked list insertion sorting of array storage structure, the element insertion is realized by modifying the pointer field of the element, and there is no need to move the data field, which avoids the defect of moving elements in batch when inserting and sorting ordinary arrays. It has relatively high efficiency. When the comparison times are still the same as that of ordinary arrays

The following is a linked list based on array storage structure. The specific sorting process is illustrated as follows:

Linked list of array storage structure - insert sorting source code

#include <stdio.h>
#include <stdlib.h>

struct Element {
  //Data domain
  int data;
  //Pointer
  int link;
};

//Encapsulate Element related properties
struct StaticList {
  int maxSize;
  // elements[0] is an additional header node
  // int *p;
  struct Element *elements;
  // The tail pointer points to the last element added to facilitate tail insertion
  int tail;
  // The avail able pointer points to the first position of the standby linked list
  int avail;
  // Indicates the number of current elements
  int currentSize;
};

int initStaticList(struct StaticList *p, int maxSize) {
  p->avail = 1;
  p->tail = 0;
  p->currentSize = 0;
  p->maxSize = maxSize > 10 ? (maxSize + 1) : 10;
  p->elements = (struct Element *)malloc(p->maxSize * sizeof(struct Element));
  for (int i = 1; i < p->maxSize; i++) {
    p->elements[i].link = i + 1;
  }
  p->elements[0].link = -1;
  p->elements[maxSize].link = -1;
}

void addElement(struct StaticList *p, int x) {
  int cur = p->avail;
  if (cur == -1) {
    printf("memory overflow");
    return;
  }
  p->avail = p->elements[cur].link;
  p->elements[cur].data = x;
  //The pointer field of the newly inserted element is - 1
  p->elements[cur].link = -1;
  p->elements[p->tail].link = cur;
  p->tail = cur;
  p->currentSize++;
}
void output(struct Element *ems) {
  int cur = ems[0].link;
  while (cur != -1) {
    printf("%d, ", ems[cur].data);
    cur = ems[cur].link;
  }
  printf("\n");
}

//Static linked list insertion sorting, from small to large
void insertSortElement(struct Element ems[]) {
  int ptr = ems[0].link;
  if (ptr == -1 || ems[ptr].link == -1) {
    return;
  }
  ptr = ems[ptr].link;
  // last records the pointer to the largest element
  int last = ems[0].link;
  // Pre and cur are pointers to the front and back nodes of the inner loop respectively
  int pre, cur;
  // ptr is used as the pointer of the outer loop, and nextptr is used as the pointer of the successor node of ptr
  int nextptr;
  while (ptr != -1) {
    pre = 0;
    cur = ems[0].link;
    //To achieve from large to small, modify to EMS [cur] data > ems[ptr]. data
    while (ems[cur].data < ems[ptr].data) {
      pre = cur;
      cur = ems[cur].link;
    }
    //Temporary EMS [PTR] Link pointer, otherwise it will be overwritten
    nextptr = ems[ptr].link;
    // The cur pointer does not point to ptr, indicating that there is an insert
    if (cur != ptr) {
      // Subsequent nodes of ptr point to cur
      ems[ptr].link = cur;
      // Subsequent nodes of pre point to ptr
      ems[pre].link = ptr;
      //The pointer field of the updated maximum element points to the latest node. If nextptr is the last node, take - 1
      ems[last].link = nextptr;
    } else {
      //If the elements are already ordered, the current pointer ptr is recorded as the pointer of the largest element
      last = ptr;
    }
    ptr = nextptr;
  }
}

int main() {
  struct StaticList p;
  int arr[] = {1, 4, 6, 7, 0, 3, 10, 9, 2, 9,
               3, 7, 4, 8, 5, 6, 1, 0, 9999, 44,
               9999, 2, 4, 9, 4, 12, 44, 99, -1, 0,
               5, 888, 345, 12344, 5555, 9090, 10000, 123, 444, -888,
               100, 400, 120000, 899999, -1, -2, 8, 9, 8};
  // int arr[]={6,4,3,8,7,5,2,1};
  // int arr[] = {2, 5, 6, 7, 1, 4, 8, 9};
  // int arr[] = {9, 0};
  int n = sizeof(arr) / sizeof(int);
  initStaticList(&p, n);
  for (int i = 0; i < n; i++) {
    addElement(&p, arr[i]);
  }
  printf("#### insert sort before ####\n");
  output(p.elements);
  printf("#### insert sort after ####\n");
  insertSortElement(p.elements);
  output(p.elements);
  free(p.elements);
  return 0;
}

Keywords: Algorithm data structure linked list

Added by olechka on Tue, 21 Dec 2021 07:46:00 +0200