排序算法基础

算法算是常见问题,经常会被提及尤其是面试(我面试别人时会问,当然被面时也会被问及,如若不去处理一些数学模型类问题,很少会被使用,但是碰到此类问题时如何选择一个优秀的算法便呢好的算法对于问题的解决相当有益)

下面看一些排序基础知识
排序:将任意序列排列成按关键字有序的序列
排序依据过程中涉及存储器的不同分为内部排序和外部排序

排序算法依据不同原则分为以下几种

1.插入排序
2.交换排序
3.选择排序
4.归并排序
5.计数排序

依据工作量不同又可分为

1.简单排序 (时间复杂度为O(n² ))
2.先进的排序算法(时间复杂度为O(nlogn))
3.基数排序(时间复杂度为O(d•n))

排序的两个基本操作
1.比较关键字(※必不可少)
2.将记录移动到合适位置(可通过存储方式避免比如链表)

待排序序列存储方式
1.线形存储
2.静态链表
3.两张表存储(我这么称呼,因为一张存放指向数据的地址,另一张存放数据,而排序时只移动地址也叫地址排序)

排序的优缺点
1.就平均时间性能而言 快排最佳,而最坏情况下不如堆排和归并排序
2.简单排序包括起泡和简单选择排序以及除希尔排序外的插入排序,尤以直接插入最为简单
3.从性能稳定性比较 基数排序及素有所有时间复杂度为O(n² )都是稳定的,快排、堆排、希尔排序时间复杂度较低的排序方法都不稳定

下面贴几个排序算法

1.快排 时间复杂度 O(nlogn) 最坏的情况时间复杂度为O(n² )

- (void)quickSort:(NSMutableArray *)array withLeftIndex:(NSInteger)leftIndex AndRightIndex:(NSInteger)rightIndex
{

    if (leftIndex >= rightIndex) {//如果数组长度为0或1时返回

        return ;

    }
    
    NSInteger i = leftIndex;

    NSInteger j = rightIndex;

    //记录比较基准数

    NSInteger key = [array[i] integerValue];

    NSLog(@"key---=== %@",array[i]);

    while (i < j) {

        /**** 首先从右边j开始查找比基准数小的值 ***/

        while (i < j && [array[j] integerValue] >= key) {//如果比基准数大,继续查找
            
            j--;
            //if ([array[j] integerValue] > [array[j+1] integerValue] ) {   /**** 改进在快排时进行冒泡 ***/
              //  [array exchangeObjectAtIndex:j withObjectAtIndex:j+1];
          //  }

        }

        //如果比基准数小,则将查找到的小值调换到i的位置

        array[i] = array[j];
        NSLog(@"array1 ====== %@",array);


        /**** 当在右边查找到一个比基准数小的值时,就从i开始往后找比基准数大的值 ***/

        while (i < j && [array[i] integerValue] <= key) {//如果比基准数小,继续查找

            i++;
          //  if ([array[i] integerValue] < [array[i-1] integerValue]) {  /**** 改进在快排时进行冒泡 ***/
          //     [array exchangeObjectAtIndex:i withObjectAtIndex:i-1];
         //   }

        }

        //如果比基准数大,则将查找到的大值调换到j的位置

        array[j] = array[i];
        NSLog(@"array2++++=== %@",array);
        

    }
    
    //将基准数放到正确位置

    array[i] = @(key);

    NSLog(@"%@",array);

    /**** 递归排序 ***/

    //排序基准数左边的
    [self quickSort:array withLeftIndex:leftIndex AndRightIndex:i-1];

    //排序基准数右边的
    [self quickSort:array withLeftIndex:i+1 AndRightIndex:rightIndex];
}

2.堆排序 时间复杂度O(nlogn)

/**堆排序(HeapSort):
 1、首先从最后一个父节点做最大堆调整,找出最大值,此时最大值位于根节点
 2、然后将最大值和已排好元素(依次找出的最大值排出的序列,如:6 3 9 23 12 8 [15 16 17 18])前一位元素交换位置,再将除已排好元素外的其他元素(6 3 9 23 12 8)做最大堆调整,找出最大值,此时最大值位于根节点
 3、重复步骤2,直至结束
 */
- (void)heapSortWithNumbers:(NSMutableArray *)numbers {
    //初始化,i从最後一个父节点开始做最大堆调整,调整结束后根节点得到最大值
    for (int i = (int)numbers.count / 2 - 1; i >= 0; i--) {
        [self maxHeapifyWithNumbers:numbers start:i end:(int)numbers.count - 1];
    }
    //先将第一个元素和已排好元素前一位做交换,再重新调整,直到排序完毕
    for (int i = (int)numbers.count - 1; i > 0; i--) {
        [numbers exchangeObjectAtIndex:0 withObjectAtIndex:i];
        [self maxHeapifyWithNumbers:numbers start:0 end:i - 1];
    }
    NSLog(@"%@",numbers);
}
//最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
- (void)maxHeapifyWithNumbers:(NSMutableArray *)numbers start:(int)start end:(int)end {
    //建立父节点指标和子节点指标
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) { //若子节点指标在范围内才做比较
        if (son + 1 <= end && [numbers[son] intValue] < [numbers[son + 1] intValue]) { //先比较两个子节点大小,选择最大的
            son++;
        }
        if ([numbers[dad] intValue] > [numbers[son] intValue]) {//如果父节点大于子节点代表调整完毕,直接跳出函数
            return;
        }else { //否则交换父子内容再继续子节点和孙节点比较
            [numbers exchangeObjectAtIndex:son withObjectAtIndex:dad];
            dad = son;
            son = dad * 2 + 1;
        }
    }
}

堆排序所用知识为二叉树 这里会提及二叉树的一些概念 满二叉树 完全二叉树的性质还需掌握B-树、B+树、红黑二叉树、赫夫曼树

3.希尔排序 (插入排序的一种)时间复杂度O(n² ) n->∞ 时间复杂度为 O(n(㏒₂n)) 最优O(n)

- (NSArray *)shellSort:(NSArray *)unsortDatas {
    NSMutableArray *unSortArray = [unsortDatas mutableCopy];
    int len = (int)unSortArray.count;
    for (int gap = floor(len / 2); gap > 0; gap = floor(gap/2)) {
        for (int i = gap; i < len; i++) {
            for (int j = i - gap; j >= 0 && [unSortArray[j] integerValue] > [unSortArray[j+gap] integerValue]; j-=gap) {
                NSNumber *temp = unSortArray[j];
                unSortArray[j] = unSortArray[gap+j];
                unSortArray[gap+j] = temp;
            }
        }
    }
    return [unSortArray copy];
}

4.归并排序 时间复杂度O(nlogn)

- (NSMutableArray *)megerSortAscendingOrderSort:(NSMutableArray *)ascendingArr
{
    //tempArray数组里存放ascendingArr个数组,每个数组包含一个元素
    NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:1];
    for (NSNumber *num in ascendingArr) {
        NSMutableArray *subArray = [NSMutableArray array];
        [subArray addObject:num];
        [tempArray addObject:subArray];
    }
    //开始合并为一个数组
    while (tempArray.count != 1) {
        NSInteger i = 0;
        while (i < tempArray.count - 1) {
            tempArray[i] = [self mergeArrayFirstList:tempArray[i] secondList:tempArray[i + 1]];
            [tempArray removeObjectAtIndex:i + 1];
            i++;
        }
    }
    NSLog(@"归并升序排序结果:%@", tempArray[0]);
    return tempArray[0];
}

- (NSArray *)mergeArrayFirstList:(NSArray *)array1 secondList:(NSArray *)array2 {
    NSMutableArray *resultArray = [NSMutableArray array];
    NSInteger firstIndex = 0, secondIndex = 0;
    while (firstIndex < array1.count && secondIndex < array2.count) {
        if ([array1[firstIndex] floatValue] < [array2[secondIndex] floatValue]) {
            [resultArray addObject:array1[firstIndex]];
            firstIndex++;
        } else {
            [resultArray addObject:array2[secondIndex]];
            secondIndex++;
        }
    }
    while (firstIndex < array1.count) {
        [resultArray addObject:array1[firstIndex]];
        firstIndex++;
    }
    while (secondIndex < array2.count) {
        [resultArray addObject:array2[secondIndex]];
        secondIndex++;
    }
    return resultArray.copy;
}

此外还有基数排序我没研究此外还有外部排序的多路平衡归并也没研究
插入排序为最简单的排序好的算法都是多种组合并且合理运用插入排序(时间复杂度及空间复杂度,大多时间复杂度优秀的算法会有较高的空间复杂度,也就是所谓的空间换时间)

哈希表:根据设定的哈希函数和处理冲突的方法将一组关键字映射到一个有限的连续的地址集上并以关键字在地址集中的“像”作为记录在表中的存储位置,这个表就是哈希表
哈希表的构造方法

  1. 直接定址法
  2. 数字分析法
  3. 平方取中
  4. 折叠
  5. 除留余数
  6. 随机数法

处理冲突的方法

  1. 开放地址
  2. 再哈希
  3. 连地址
  4. 建立公共益处区

这些待以后研究后慢慢补充 不得不说大学有三本书很重要
《数据结构》《操作系统》《编译原理》 这是我没有丢的三本书
还是偶尔要翻出来看看,经常不用就会忘记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值