常见的八种排序方式

八种排序的时间复杂度:

排序法平均时间最差情形稳定度额外空间备注
冒泡O(n2)    O(n2)稳定O(1)n小时较好
选择O(n2)O(n2)不稳定O(1)n小时较好
插入O(n2)O(n2)稳定O(1)大部分已排序时较好
基数O(logRB)O(logRB)稳定O(n)

B是真数(0-9),

R是基数(个十百)

ShellO(nlogn)O(ns) 1<s<2不稳定O(1)s是所选分组
快速O(nlogn)O(n2)不稳定O(nlogn)n大时较好
归并O(nlogn)O(nlogn)稳定O(1)n大时较好
O(nlogn)O(nlogn)不稳定O(1)n大时较好

 

冒泡排序(Bubble Sort):

传统的冒泡排序需要依次比较相邻的两个元素,按照升序或者降序的规则进行交换,如要让 3 2 1三个数进行升序排序,首先从3开始跟2比较大于2进行交换,然后在与1进行比较,进行交换,第一趟排序结果就是2 1 3;然后 2与1比较大于1交换,2与3比较小于3不变。这就是冒泡排序的原理。然而,如果是让 3 2 1进行降序排序呢,还要再从头到尾比较一边岂不是很浪费空间,此时我们就可以使用一个 flag标记来对冒泡排序进行排序。具体方法我们来看一下代码。

演示:

代码:

一般的冒泡排序:

int arr[]={6,2,3,4,0};
        int change=0;
 
        for(int i=0;i<arr.length-1;i++){
            for(int j=0;j<arr.length-1-i;j++){
                if(arr[j]>arr[j+1]){
                
                    change=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=change;
                }
            }

       

            System.out.println("第"+(i+1)+"趟"+Arrays.toString(arr));
        }

通过标记 flag来判断 是否进行了交换,如果没有则直接退出循环,从而达到了对排序的进一步优化。

优化后的冒泡排序:

int arr[]={6,2,3,4,0};
        int change=0;
        Boolean flag=false;
        for(int i=0;i<arr.length-1;i++){
            for(int j=0;j<arr.length-1-i;j++){
                if(arr[j]>arr[j+1]){
                    flag=true;
                    change=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=change;
                }
            }

            if(!flag){
                break;
            }else {
                flag=false;
            }

            System.out.println("第"+(i+1)+"趟"+Arrays.toString(arr));
        }

选择排序(Select Sort):

第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。

假设序列第一个位置为最小,然后依次和后面的元素进行比较,比第一个元素小的元素就设个标记再往后依次比较,直到找到最小值然后与第一个位置元素进行交换。

演示:

代码:

    int[] arry= {7,4,8,3};
        for(int i = 0;i<arry.length-1;i++){
            int minIndex=i;
            int minArry=arry[i];

            for (int j = i+1;j<arry.length;j++){
                if(minArry>arry[j]){
                    minIndex=j;

                    minArry=arry[j];

                }

            }
            if(minIndex!=i){
                arry[minIndex]=arry[i];
                arry[i]=minArry;
            }
            System.out.println(Arrays.toString(arry));
        }

用过代码我们不难发现冒泡排序和选择排序的时间复杂度都是O(n²),接下来我们看一下他们的区别:

(1)冒泡排序是比较相邻位置的两个数,而选择排序是按顺序比较,找最大值或者最小值;

(2)冒泡排序每一轮比较后,位置不对都需要换位置,选择排序每一轮比较都只需要换一次位置;

(3)冒泡排序是通过数去找位置,选择排序是给定位置去找数;

 冒泡排序优缺点:优点:比较简单,空间复杂度较低,是稳定的;
                              缺点:时间复杂度太高,效率慢;

选择排序优缺点:优点:一轮比较只需要换一次位置;

                             缺点:效率慢,不稳定(举个例子5,8,5,2,9   我们知道第一遍选择第一个元素5会和2交换,那么原序列中2个5的相对位置前后顺序就破坏了)

 

插入排序(Inser Sort):

插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。

 在一个数组中我们开始把第一个元素看为是一个排好序的队列,剩余的看为是乱序的序列,在剩余的队列中依次选取元素与前面队列进行比较再尔进行排序,至此我们就保证前面的元素永远都是有序的,从而达到插入排序的效果。

演示:

代码:

    int arry[]={7,5,4,3,2};

        for(int i=1;i<arry.length;i++){
            int insertVal = arry[i];
            int insertIndex=i-1;

            while(insertIndex >= 0 && insertVal<arry[insertIndex]){
                arry[insertIndex+1]=arry[insertIndex];
                insertIndex--;
            }
                arry[insertIndex+1]=insertVal;
      
            System.out.println(Arrays.toString(arry));
        }

 

优化后的代码:

优化后的代码我们可以发现,通过insertIndex是否变化 来判断while循环是否执行,从而避免不必要的赋值。

    int arry[]={7,5,4,3,2};

        for(int i=1;i<arry.length;i++){
            int insertVal = arry[i];
            int insertIndex=i-1;

            while(insertIndex >= 0 && insertVal<arry[insertIndex]){
                arry[insertIndex+1]=arry[insertIndex];
                insertIndex--;
            }
            if(insertIndex+1!=i){ //此时无需交换
                arry[insertIndex+1]=insertVal;
            }

            System.out.println(Arrays.toString(arry));
        }

希尔排序(Shell Sort):

对于简单插入排序,存在一个效率的问题如2,3,4,5,1这个数组,使用插入排序他的顺序是

{2 3 4 5 5}
{2 3 4 4 5}
{2 3 3 4 5}
{2 2 3 4 5}
{1 2 3 4 5}  不难看出 我们只需要换一个数然后过程执行了五次,对效率有很大影响,此时我们可以引入一种改进后的插入排序,那就是希尔排序,也叫缩小增量排序。

希尔排序就是按照下标一定增量进行分组,每组再按照直接插入算法排序,随着组的减少,每组的元素也越来越少,当组数减少至为1时,整个文件分成1组,算法便终止。

演示:

代码:

(交换法)

package sort;

import java.util.Arrays;

public class ShellSort {
    public static void main(String[] args) {
        int temp=0;
        int arry[]={3,2,1,6,5,7,8,4,9,0};
        // gap代表分了多少组
        for(int gap =arry.length/2;gap>0;gap/=2){
            //i代表第几组开始是 第0 6个 1 7个  2 8个 3 9个 4 10个为一组
            for (int i=gap;i<arry.length;i++){
                //j代表第几组的第几个元素
                for(int j=i-gap;j>=0;j-=gap){
                    if(arry[j]>arry[j+gap]){
                        temp=arry[j];
                        arry[j]=arry[j+gap];
                        arry[j+gap]=temp;
                    }
                }
            }
            System.out.println(Arrays.toString(arry));
        }

    }
}

(移步法)

  int arry[]={3,2,1,6,5,7,8,4,9,0};


        // gap代表分了多少组
        for(int gap =arry.length/2;gap>0;gap/=2){
            //i代表第几组开始是 第0 6个 1 7个  2 8个 3 9个 4 10个为一组 共五个组那么0 和6肯定为一组
            for (int i=gap;i<arry.length;i++){
            int j=i;
            int temp=arry[j];
            if(arry[j]<arry[j-gap]){
                 while(j-gap>=0 && temp < arry[j - gap]){
                     arry[j]=arry[j-gap];
                     j-=gap;
                 }
                 arry[j]=temp;
            }
            }
            System.out.println(Arrays.toString(arry));
        }
    }

快速排序(Quick Sort):

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。大致意思就是在一个数组中取中间元素比它小的方左边比它大的则放右边 两边元素再按照快排要求,最终变成有序序列。

演示:

代码:

public static void quickSort(int[] arr, int left, int right) {
		int l = left;// 左下标
		int r = right;// 右下标
		int pivot = arr[(left + right) / 2];// 找到中间的值
		// 将比pivot小的值放在其左边,比pivot大的值放在其右边
		while (l < r) {
			// 在pivot左边寻找,直至找到大于等于pivot的值才退出
			while (arr[l] < pivot) {
				l += 1;// 将l右移一位
			}
			// 在pivot右边寻找,直至找到小于等于pivot的值才退出
			while (arr[r] > pivot) {
				r -= 1;// 将r左移一位
			}
			if (l >= r) {
				// 左右下标重合,寻找完毕,退出循环
				break;
			}
			// 交换元素
			int temp = arr[l];
			arr[l] = arr[r];
			arr[r] = temp;

			//倘若发现值相等的情况,则没有比较的必要,直接移动下标即可
		
			// 如果交换完后,发现arr[l]==pivot,此时应将r左移一位
			if (arr[l] == pivot) {
				r -= 1;
			}
			// 如果交换完后,发现arr[r]==pivot,此时应将l右移一位
			if (arr[r] == pivot) {
				l += 1;
			}
		}
		// 如果l==r,要把这两个下标错开,否则会出现无限递归,导致栈溢出的情况
		if (l == r) {
			l += 1;
			r -= 1;
		}
		// 向左递归
		if (left < r) {
			quickSort(arr, left, r);
		}
		// 向右递归
		if (right > l) {
			quickSort(arr, l, right);
		}
	}

 

归并排序(Merge Sort):

 

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
 

 

演示:

代码:

public static void mergeSort(int[] arr, int left, int right, int[] temp) {
		// 分解
		if (left < right) {
			int mid = (left + right) / 2;// 中间索引
			// 向左递归进行分解
			mergeSort(arr, left, mid, temp);
			// 向右递归进行分解
			mergeSort(arr, mid + 1, right, temp);// mid + 1,中间位置的后一个位置才是右边序列的开始位置
			// 每分解一轮便合并一轮
			merge(arr, left, right, mid, temp);
		}
	}

	/**
	 * 合并的方法
	 * 
	 * @param arr   待排序的数组
	 * @param left  左边有序序列的初始索引
	 * @param right 中间索引
	 * @param mid   右边有序序列的初始索引
	 * @param temp  做中转的数组
	 */
	public static void merge(int[] arr, int left, int right, int mid, int[] temp) {
		int i = left; // 初始化i,左边有序序列的初始索引
		int j = mid + 1;// 初始化j,右边有序序列的初始索引(右边有序序列的初始位置即为中间位置的后一个位置)
		int t = 0;// 指向temp数组的当前索引,初始为0
		// 先把左右两边的数据(已经有序)按规则填充到temp数组
		// 直到左右两边的有序序列,有一边处理完成为止
		while (i <= mid && j <= right) {
			// 如果左边有序序列的当前元素小于或等于右边有序序列的当前元素,就将左边的元素填充到temp数组中
			if (arr[i] <= arr[j]) {
				temp[t] = arr[i];
				t++;// 索引后移
				i++;// i后移
			} else {
				// 反之,将右边有序序列的当前元素填充到temp数组中
				temp[t] = arr[j];
				t++;// 索引后移
				j++;// j后移
			}
		}
		// 把有剩余数据的一边的元素填充到temp中
		while (i <= mid) {
			// 此时说明左边序列还有剩余元素
			// 全部填充到temp数组
			temp[t] = arr[i];
			t++;
			i++;
		}
		while (j <= right) {
			// 此时说明左边序列还有剩余元素
			// 全部填充到temp数组
			temp[t] = arr[j];
			t++;
			j++;
		}
		// 将temp数组的元素复制到原数组
		t = 0;
		int tempLeft = left;
		while (tempLeft <= right) {
			arr[tempLeft] = temp[t];
			t++;
			tempLeft++;
		}
	}

 

基数排序(radix sort):

基数排序会分配是个桶 标号分别是0-9,在第一次排序时会将每个元素的个位取出,放到相应编号的桶中,然后按照桶的顺序依次放回原来的数组;进行第二次排序时,会将每个元素的十位取出放到相应编号的桶中,然后按照桶的顺序依次放回原来的数组;以此类推直到最高位排完,排序也就完成。

演示:

数组{718,34,72,401,64}进行基数排序

 

第一趟排序结果{ 401 ,72 ,34 , 64,718}

第二趟排序结果{401,718,34,64,72}

第三趟排序结果{34,64,72,401,718}  排序完成 将元素返回原数组

 

代码:

public static void raixSort(int[] arr) {
		// 第一轮(针对每个元素的个位进行排序处理)

		// 定义一个二维数组,模拟桶,每个桶就是一个一维数组
		// 为了防止放入数据的时候桶溢出,我们应该尽量将桶的容量设置得大一些
		int[][] bucket = new int[10][arr.length];
		// 记录每个桶中实际存放的元素个数
		// 定义一个一维数组来记录每个桶中每次放入的元素个数
		int[] bucketElementCounts = new int[10];

		for (int j = 0; j < arr.length; j++) {
			// 取出每个元素的个位
			int digitOfElement = arr[j] % 10;
			// 将元素放入对应的桶中
			// bucketElementCounts[digitOfElement]就是桶中的元素个数,初始为0,放在第一位
			bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
			// 将桶中的元素个数++
			// 这样接下来的元素就可以排在前面的元素后面
			bucketElementCounts[digitOfElement]++;
		}
		// 按照桶的顺序取出数据并放回原数组
		int index = 0;
		for (int k = 0; k < bucket.length; k++) {
			// 如果桶中有数据,才取出放回原数组
			if (bucketElementCounts[k] != 0) {
				// 说明桶中有数据,对该桶进行遍历
				for (int l = 0; l < bucketElementCounts[k]; l++) {
					// 取出元素放回原数组
					arr[index++] = bucket[k][l];
				}
			}
			// 第一轮处理后,需要将每个bucketElementCounts[k]置0
			bucketElementCounts[k] = 0;
		}
		System.out.println("第一轮:" + Arrays.toString(arr));

		// ----------------------------

		// 第二轮(针对每个元素的十位进行排序处理)
		for (int j = 0; j < arr.length; j++) {
			// 取出每个元素的十位
			int digitOfElement = arr[j] / 10 % 10;
			// 将元素放入对应的桶中
			// bucketElementCounts[digitOfElement]就是桶中的元素个数,初始为0,放在第一位
			bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
			// 将桶中的元素个数++
			// 这样接下来的元素就可以排在前面的元素后面
			bucketElementCounts[digitOfElement]++;
		}
		// 按照桶的顺序取出数据并放回原数组
		index = 0;
		for (int k = 0; k < bucket.length; k++) {
			// 如果桶中有数据,才取出放回原数组
			if (bucketElementCounts[k] != 0) {
				// 说明桶中有数据,对该桶进行遍历
				for (int l = 0; l < bucketElementCounts[k]; l++) {
					// 取出元素放回原数组
					arr[index++] = bucket[k][l];
				}
			}
			// 第二轮处理后,需要将每个bucketElementCounts[k]置0
			bucketElementCounts[k] = 0;
		}
		System.out.println("第二轮:" + Arrays.toString(arr));

		// ----------------------------

		// 第三轮(针对每个元素的百位进行排序处理)
		for (int j = 0; j < arr.length; j++) {
			// 取出每个元素的百位
			int digitOfElement = arr[j] / 100 % 10;
			// 将元素放入对应的桶中
			// bucketElementCounts[digitOfElement]就是桶中的元素个数,初始为0,放在第一位
			bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
			// 将桶中的元素个数++
			// 这样接下来的元素就可以排在前面的元素后面
			bucketElementCounts[digitOfElement]++;
		}
		// 按照桶的顺序取出数据并放回原数组
		index = 0;
		for (int k = 0; k < bucket.length; k++) {
			// 如果桶中有数据,才取出放回原数组
			if (bucketElementCounts[k] != 0) {
				// 说明桶中有数据,对该桶进行遍历
				for (int l = 0; l < bucketElementCounts[k]; l++) {
					// 取出元素放回原数组
					arr[index++] = bucket[k][l];
				}
			}
			// 第三轮处理后,需要将每个bucketElementCounts[k]置0
			bucketElementCounts[k] = 0;
		}
		System.out.println("第三轮:" + Arrays.toString(arr));
	}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 23
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C 语言编程常见问题解答 【作者】[美]Paul S.R. Chisholm 译:张芳妮 吕 波 【出版社】清华大学出版社 C语言编程常见问题解答(目录) 第l章 C语言 1. 1 什么是局部程序块(local block)? 1. 2 可以把变量保存在局部程序块中吗? 1. 3 什么时候用一条switch语句比用多条if语句更好? 1. 4 switch语句必须包含default分支吗? 1. 5 switch语句的最后—个分支可以不要break语句吗? 1. 6 除了在for语句中之外,在哪些情况下还要使用逗号运算? 1. 7 怎样才能知道循环是否提前结束了? 1. 8 goto,longjmp()和setjmp()之间有什么区别? 1. 9 什么是左值(lvaule)? 1. 10 数组(array)可以是左值吗? 1. 11 什么是右值(rvaule)? 1. 12 运算符的优先级总能保证是“自左至右”或“自右至左”的顺序吗? 1. 13 ++var和var++有什么区别? 1. 14 取模运算符(modulusoperator)“%”的作用是什么? 第2章 变量和数据存储 2. 1 变量存储在内存(memory)中的什么地方? 2. 2 变量必须初始化吗? 2. 3 什么是页抖动(pagethrashing)? 2. 4 什么是const指针? 2. 5 什么时候应该使用register修饰符?它真的有用吗? 2. 6 什么时候应该使用volatile修饰符? 2. 7 一个变量可以同时被说明为const和volatile吗? 2. 8 什么时候应该使用const修饰符? 2. 9 浮点数比较(floating—point comparisons)的可靠性如何? 2. 10 怎样判断一个数字型变量可以容纳的最大值? 2. 11 对不同类型的变量进行算术运算会有问题吗? 2. 12 什么是运算符升级(operator promotion)? 2. 13 什么时候应该使用类型强制转换(typecast)? 2. 14 什么时候不应该使用类型强制转换(typecast)? 2. 15 可以在头文件中说明或定义变量吗? 2. 16 说明一个变量和定义一个变量有什么区别? 2. 17 可以在头文件中说明static变量吗? 2.18 用const说明常量有什么好处? 第3章 排序与查找 排 序 查 找 排序或查找的性能 3.1 哪一种排序方法最方便? 3.2 哪一种排序方法最快? 3.3 当要排序的数据集因太大而无法全部装入内存时,应怎样排序? 3.4 哪一种查找方法最方便? 3.5 哪一种查找方法最快? 3.6 什么是哈希查找? 3.7 怎样对链表进行排序? 3.8 怎样查找链表中的数据? 第4章 数据文件 4.1 当errno为一个非零值时,是否有错误发生? 4.2 什么是流(stream)? 4.3 怎样重定向—个标准流? 4.4 怎样恢复一个重定向了的标准流? 4.5 stdout能被强制打印到非屏幕设备上吗? 4.6 文本模式(text mode)和二进制模式(binary mode)有什么区别? 4.7 怎样判断是使用流函数还是使用低级函数? 4.8 怎样列出某个目录下的文件? 4.9 怎样列出—个文件的日期和时间? 4.10 怎样对某个目录下的文件名进行排序? 4.1l 怎样判断一个文件的属性? 4.12 怎样查看PATH环境变量? 4.13 怎样打开一个同时能被其它程序修改的文件? 4.14 怎样确保只有你的程序能存取一个文件? 4.15 怎样防止其它程序修改你正在修改的那部分文件内容? 4.16 怎样—次打开20个以上的文件? 4.17 怎样避开"Abort,Retry,Fail"消息? 4.18 怎样读写以逗号分界的文本? 第5章 编译预处理 5.1 什么是宏(macro)?怎样使用宏? 5.2 预处理程序(preprocessor)有什么作用? 5.3 怎样避免多次包含同—个头文件? 5.4 可以用#include指令包含类型名不是“.h”的文件吗? 5.5 用#define指令说明常量有什么好处? 5.6 用enum关键字说明常量有什么好处? 5.7 与用#define指令说明常量相比,用enum关键字说明常量有什么好处? 5.8 如何使部分程序在演示版中失效? 5.9 什么时候应该用宏代替函数? 5.10 使用宏更好,还是使用函数更好? 5.11 在程序中加入注释的最好方法是什么? 5.12 #include<file>和#include“file”有什么不同? 5.13 你能指定在编译时包含哪一个头文件吗? 5.14 包含文件可以嵌套吗? 5.15 包含文件最多可以嵌套几层? 5.16 连接运算符“##”有什么作用? 5.17 怎样建立对类型敏感的宏? 5.18 什么是标准预定义宏? 5.19 怎样才能使程序打印出发生错误的行号? 5.20 怎样才能使程序打印出发生错误的源文件名? 5.2l 怎样判断一个程序是用C编译程序环是用C++编译程序编译的? 5.22 预处理指令#pragma有什么作用? 5.23 #line有什么作用? 5.24 标准预定义宏_FILE_有什么作用? 5.25 怎样在程序中打印源文件名? 5.26 标准预定义宏_LINE_有什么作用? 5.27 怎样在程序中打印源文件的当前行号? 5.28 标准预定义宏_DATE_和_TIME_有什么作用? 5.29 怎样在程序中打印编译日期和时间? 5.30 怎样判断一个程序是否遵循ANSIC标准? 5.31 怎样取消一个已定义的宏? 5.32 怎样检查一个符号是否已被定义? 5.33 C语言提供哪些常用的宏? 第6章 字符串操作 6.l 串拷贝(strcpy)和内存拷贝(memcpy)有什么不同?它们适合于在哪种情况下使用? 6.2 怎样删去字符串尾部的空格? 6.3 怎样删去字符串头部的空格? 6.4 怎样使字符串右对齐? 6.5 怎样将字符串打印成指定长度? 6.6 怎样拷贝字符串的一部分? 6.7 怎样将数字转换为字符串? 6.8 怎样将字符串转换为数字? 6.9 怎样打印字符串的一部分? 6.10 怎样判判断两个字符串是否相同? 第7章 指针和内存分配 7.1 什么是间接引用(indirection)? 7.2 最多可以使用几层指针? 7.3 什么是空指针? 7.4 什么时候使用空指针? 7.5 什么是void指针? 7.6 什么时候使用void指针? 7.7 两个指针可以相减吗?为什么? 7.8 把一个值加到一个指针上意味着什么? 7.9 NULL总是被定义为0吗? 7.10 NULL总是等于0吗? 7.11 用指针作if语句的条件表达式意味着什么? 7.12 两个指针可以相加吗?为什么? 7.13 怎样使用指向函数的指针? 7.14 怎样用指向函数的指针作函数的参数? 7.15 数组的大小可以在程序运行时定义吗? 7.16 用malloc()函数更好还是用calloc()函数更好? 7.17 怎样说明一个大于64KB的数组? 7.18 far和near之间有什么区别? 7.19 什么时候使用far指针? 7.20 什么是栈(stack)? 7.21 什么是堆(heap)? 7.22 两次释放一个指针会导致什么结果? 7.23 NULL和NUL有什么不同? 7.24 为什么不能给空指针赋值?什么是总线错误、内存错误和内存信息转储? 7.25 怎样确定一块已分配的内存的大小? 7.26 free()函数是怎样知道要释放的内存块的大小的? 7.27 可以对void指针进行算术运算吗? 7.28 怎样打印一个地址? 第8章 函数 8.1 什么时候说明函数? 8.2 为什么要说明函数原型? 8.3 一个函数可以有多少个参数? 8.4 什么是内部函数? 8.5 如果一个函数没有返回值,是否需要加入return语句? 8.6 怎样把数组作为参数传递给函数? 8.7 在程序退出main()函数之后,还有可能执行一部分代码吗? 8.8 用PASCAL修饰符说明的函数与普通C函数有什么不同? 8.9 exit()和return有什么不同? . 第9章 数组 9.1 数组的下标总是从0开始吗? 9.2 可以使用数组后面第—个元素的地址吗? 9.3 为什么要小心对待位于数组后面的那些元素的地址呢? 9.4 在把数组作为参数传递给函数时,可以通过sizeof运算符告诉函数数组的大小吗? 9.5 通过指针或带下标的数组名都可以访问数组中的元素,哪一种方式更好呢? 9.6 可以把另外一个地址赋给一个数组名吗? 9.7 array_name和&array;_name有什么不同? 9.8 为什么用const说明的常量不能用来定义一个数组的初始大小? 9.9 字符串和数组有什么不同? 第10章 位(bit)和字节(byte) 10.1 用什么方法存储标志(flag)效率最高? 10.2 什么是“位屏蔽(bit masking)”? 10.3 位域(bit fields)是可移植的吗? 10.4 移位和乘以2这两种方式中哪一种更好? 10.5 什么是高位字节(high-order byte)和低位字节(low-order byte)? 10.6 16位和32位的数是怎样存储的? 第11章 调试 11.1 如果我运行的程序挂起了,应该怎么办? 11.2 如何检测内存漏洞(leak)? 11.3 调试程序的最好方法是什么? 11.4 怎样调试TSR程序? 11.5 怎样获得一个能报告条件失败的程序? 第12章 标准库函数 12.1 为什么应该使用标准库函数而不要自己编写函数? 12.2 为了定义我要使用的标准库函数,我需要使用哪些头文件? 12.3 怎样编写参数数目可变的函数? 12.4 独立(free—standing)环境和宿主(hosted)环境之间有什么区别? 12.5 对字符串进行操作的标准库函数有哪些? 12.6 对内存进行操作的标准库函数有哪些? 12.7 怎样判断一个字符是数字、字母或其它类别的符号? 12.8 什么是“局部环境(locale)”? 12.9 有没有办法从一个或多个函数中跳出? 12.10 什么是信号(signal)?用信号能做什么? 12.11 为什么变量名不能以下划线开始? 12.12 为什么编译程序提供了两个版本的malloc()函数? 12.13 适用于整数和浮点数的数学函数分别有哪些? 12.14 什么是多字节字符(multibyte characters)? 12.15 怎样操作由多字节字符组成的字符串? 第13章 时间和日期 13.1 怎样把日期存储到单个数字中?有这方面的标准吗? 13.2 怎样把时间存储到单个数字中?有这方面的标准吗? 13.3 为什么定义了这么多不同的时间标准? 13.4 存储日期的最好方法是哪一种? 13.5 存储时间的最好方法是哪一种? 第14章 系统调用 14.1 怎样检查环境变量(environment variables)的值? 14.2 怎样在程序中调用DOS函数? 14.3 怎样在程序中调用BIOS函数? 14.4 怎样在程序中存取重要的DOS内存位置? 14.5 什么是BIOS? 14.6 什么是中断? 14.7 使用ANSI函数和使用BIOS函数,哪种方式更好? 14.8 可以通过BIOS把显示模式改为VGA图形模式吗? 14.9 运算符的优先级总能起作用吗(从左至右,从右至左)? 14.10 函数参数的类型必须在函数头部或紧跟在其后说明吗?为什么? 14.11 程序应该总是包含main()的一个原型吗? 14.12 main()应该总是返回一个值吗? 14.13 可以通过BIOS控制鼠标吗? 第15章 可移植性 15.1 编译程序中的C++扩充功能可以用在C程序中吗? 15.2 C++和C有什么区别? 15.3 在C程序中可以用“∥”作注释符吗? 15.4 char,short,int和long类型分别有多长? 15.5 高位优先(big-endian)与低位优先(little—endian)的计算机有什么区别? 第16章 ANSI/ISO标准 16.1 运算符的优先级总能起作用吗? 16.2 函数参数类型必须在函数参数表中或紧跟其后的部分中说明吗? 16.3 程序中必须包含main()的原型吗? 16.4 main()应该总是返回一个值吗? 第17章 用户界面——屏幕和键盘 17.1 为什么直到程序结束时才看到屏幕输出? 17.2 怎样在屏幕上定位光标? 17.3 向屏幕上写数据的最简单的方法是什么? 17.4 向屏幕上写文本的最快的方法是什么? 17.5 怎样防止用户用Ctr+Break键中止程序的运行? 17.6 怎样才能只得到一种特定类型的数据,例如字符型数据? 17.7 为什么有时不应该用scanf()来接收数据? 17.8 怎样在程序中使用功能键和箭头键? 17.9 怎样防止用户向一个内存区域中输入过多的字符? 17.10 怎样用0补齐一个数字? 17.11 怎样才能打印出美元一美分值? 17.12 怎样按科学记数法打印数字? 17.13 什么是ANSI驱动程序? 17.14 怎样通过ANSI驱动程序来清屏? 17.15 怎样通过ANSI驱动程序来存储光标位置? 17.16 怎样通过ANSI驱动程序来恢复光标位置? 17.17 怎样通过ANSI驱动程序来改变屏幕颜色? 17.18 怎样通过ANSI驱动程序来写带有颜色的文本? 17.19 怎样通过ANSI驱动程序来移动光标? 第18章 程序的编写和编译 18.1 程序是应该写成一个源文件还是多个源文件? 18.2 各种存储模式之间有什么区别? 18.3 最常使用的存储模式有哪些? 18.4 应该使用哪种存储模式? 18.5 怎样生成一个".COM"文件? 18.6 ".COM"文件有哪些地方优于".EXE"文件? 18.7 当一个库被连接到目标上时,库中的所有函数是否都会被加到一个".EXE"文件中? 18.8 可以把多个库函数包含在同一个源文件中吗? 18.9 为什么要建立一个库? 18.10 如果一个程序包含多个源文件,怎样使它们都能正常工作? 18.11 连接过程中出现"DGROUP:group exceeds 64K"消息是怎么回事? 18.12 怎样防止程序用尽内存? 18.13 如果程序太大而不能在DOS下运行,怎样才能使它在DOS下运行呢? 18.14 怎样才能使DOS程序获得超过640KB的可用内存呢? 18.15 近程型(near)和远程型(far)的区别是什么? 第19章编程风格和标准 19.1 可以在变量名中使用下划线吗? 19.2 可以用变量名来指示变量的数据类型吗? 19.3 使用注释会影响程序的速度、大小或效率吗? 19.4 使用空白符会影响程序的速度、大小或效率吗? 19.5 什么是骆驼式命名法? 19.6 较长的变量名会影响程序的速度、大小或效率吗? 19.7 给函数命名的正确方法是什么? 19.8 使用大括号的正确方法是什么? 19.9 一个变量名应该使用多少个字母?ANSI。标准允许有多少个有效字符? 19.10 什么是匈牙利式命名法?应该使用它吗? 19.11 什么是重复处理(iterative processing)? 19.12 什么是递归(recursion)?怎样使用递归? 19.13 在C语言中,表示真和假的最好方法是什么? 19.14 空循环(null loops)和无穷循环(infinite loops)有什么区别? 19.15 continue和break有什么区别? 第20章 杂项(Miscellaneous) 20.1 怎样获得命令行参数? 20.2 程序总是可以使用命令行参数吗? 20.3“异常处理(exception handling)”和“结构化异常处理(structured exception handling)”有什么区别? 20.4 怎样在DOS程序中建立一个延时器(delay timer)? 20.5 Kernighan和Ritchie是谁? 20.6 怎样产生随机数? 20.7 什么时候应该使用32位编译程序? 20.8 怎样中断一个Windows程序? 20.9 为什么要使用静态变量? 20.10 怎样在一个程序后面运行另一个程序? 20.11 怎样在一个程序执行期间运行另一个程序? 20.12 怎样把数据从一个程序传给另一个程序? 20.13 怎样判断正在运行的程序所在的目录? 20.14 怎样找到程序中的重要文件(数据库,配置文件,等等)? 20.15 本书的有些例子程序有许多缺陷,为什么不把它们写得更好? 20.16 怎样使用Ctr+Break失效? 20.17 可以使热启动(Ctrl+Alt+Delete)失效吗? 20.18 怎样判断一个字符是否是一个字母? 20.19 怎样判断一个字符是否是一个数字? 20.20 怎样把一个十六进制的值赋给一个变量? 20. 21 怎样把一个八进制的值赋给一个变量? 20.22 什么是二进制? 20.23 什么是八进制? 20.24 什么是十六进制? 20.25 什么是换码符(escape characters)? 附 录 常用函数的包含文件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值