《Java数据结构跟算法》第二版 Robert lafore 编程作业 第七章

《Java数据结构和算法》第二版 Robert lafore 编程作业 第七章

《Java数据结构和算法》第二版 Robert lafore  编程作业 第六章

/*
 	7.1	修改partition.java程序(清单7.2),使partitionIt()方法总是用具有最大的
 		下标值的数组(最右)数据项作为枢纽,而不是任意一个数据项。(这和清单7.3
 		的quickSort.java程序相似。)确保程序对三个或少于三个数据项的数组也能
 		执行。为了达到这个目的,需要增加一些额外的语句。
 	7.2	修改quickSort2.java程序(清单7.4)以计算排序中复制和比较的次数,然后显
 		示总数。这个程序应该和QuickSort2专题applet的执行性能相同,因此对逆序
 		排列数据的复制和比较次数是一致的。(记住一次交换是三个复制。)
 		(7.2题没有做)
 	7.3	在第3章练习题3.2中,提示可以通过排序数据和挑选中间数据项来求一个数据
 		集的中心值。读者可能会想,使用快速排序然后选择一个中间的数据项是找中
 		心值最快的方法,但是还有一个更快的方法。利用划分算法求中心值,而不必
 		对所有的数据项排序。为了理解它是如何实现的,假设在划分数据时,偶然发
 		现枢纽最后停在数组中间的位置上。工作就完成了!枢纽右边的所有数据项都
 		大于(或等于)枢纽,而所有左边的数据项都小于(或等于)枢纽,所以如果
 		枢纽停在数组正中间的位置上,那么它就是中心值。枢纽通常是不会停在数组
 		中间位置上的,但是可以通过再划分包含了中间位置数据项的分组来找到它。
 		假设数组有7个数据项分布在数组的关键字从0到6的单元中。中间位置的数据项
 		的下标为3。如果划分这个数组,并且枢纽停在下标为4的位置上,那么需要对
 		下标为0到4的数据项重新划分(这个划分包含了下标为3的数据项),而不包括
 		下标为5到6的数据项。如果枢纽停在下标为2的分区,总是检查枢纽是否在中间
 		的位置。最后,枢纽会停在中间位置上的,程序也就结束。因为所需要的划分
 		次数比快速排序少,所以这个算法更快。
 		扩展编程作业7.1,来查找一个数组的中心值数据项。可以使用类似快速排序的
 		递归调用,但是只用来划分子数组,而不是对整个数组排序。当找到中心值数
 		据项时这个过程就停止,而不必等数组排序完成之后才停止。
 	7.4	选择的意思是从一个数组中找出第k大或者第k小的数据项。例如,要选择第7大
 		的数据项。找中心值(如编程作业7.2)是选择的一种特殊情况。可以使用同样
 		的划分过程,但不是找中间位置的数据项,而是找一个指定下标的数据项。修
 		改编程作业7.2中的程序,允许选择任意一个指定数据项。你的程序能处理多少
 		的数组呢?
 	7.5	实现本章最后一节所讲的基数排序算法。它应该能处理不同数据量的数据项,
 		以及关键字位数不同的数据。同时,也应该能够实现不同基数的排序(可以是
 		10以外的其他数),但是,除非编写的程序能显示不同的基数值,否则会很难
 		看清运行的情况。
 */
package chap07;

// partition.java
// demonstrates partitioning an array
// to run this program: C>java PartitionApp
////////////////////////////////////////////////////////////////
class ArrayPar {
	private long[] theArray;          // ref to array theArray
	private int nElems;               // number of data items

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

	public ArrayPar(int max)          // constructor
	{
		theArray = new long[max];      // create the array
		nElems = 0;                    // no items yet
	}

	// --------------------------
	public void insert(long value)    // put element into array
	{
		theArray[nElems] = value;      // insert it
		nElems++;                      // increment size
	}

	// --------------------------
	public int size()                 // return number of items
	{
		return nElems;
	}

	// --------------------------
	public void display()             // displays array contents
	{
		System.out.print("A=");
		for (int j = 0; j < nElems; j++)
			// for each element,
			System.out.print(theArray[j] + " ");  // display it
		System.out.println("");
	}

	// --------------------------
	public int partitionIt(int left, int right, long pivot) {
		int leftPtr = left - 1;           // right of first elem
		int rightPtr = right + 1;         // left of pivot
		while (true) {
			while (leftPtr < right &&       // find bigger item
					theArray[++leftPtr] < pivot)
				;  // (nop)

			while (rightPtr > left &&       // find smaller item
					theArray[--rightPtr] > pivot)
				;  // (nop)
			if (leftPtr >= rightPtr)        // if pointers cross,
				break;                      // partition done
			else
				// not crossed, so
				swap(leftPtr, rightPtr);    // swap elements
		}  // end while(true)
		return leftPtr;                   // return partition
	}  // end partitionIt()

	// =============================================================
	// 编程作业 7.1
	public int partitionIt(int left, int right) {
		int leftPtr = left - 1;           // right of first elem
		int rightPtr = right;         	  // left of pivot
		long pivot = theArray[right];
		while (true) {
			while (leftPtr < right &&       // find bigger item
					theArray[++leftPtr] < pivot)
				;  // (nop)

			while (rightPtr > left &&       // find smaller item
					theArray[--rightPtr] > pivot)
				;  // (nop)
			if (leftPtr >= rightPtr)        // if pointers cross,
				break;                      // partition done
			else
				// not crossed, so
				swap(leftPtr, rightPtr);    // swap elements
		}  // end while(true)
		swap(leftPtr, right);
		return leftPtr;                   // return partition
	}  // end partitionIt()

	// =============================================================
	// 编程作业 7.3
	public int findMedian(int left, int right) {
		int leftPtr = left - 1;           // right of first elem
		int rightPtr = right;         	  // left of pivot
		long pivot = theArray[right];
		while (true) {
			while (leftPtr < right &&       // find bigger item
					theArray[++leftPtr] < pivot)
				;  // (nop)

			while (rightPtr > left &&       // find smaller item
					theArray[--rightPtr] > pivot)
				;  // (nop)
			if (leftPtr >= rightPtr)        // if pointers cross,
				break;                      // partition done
			else
				// not crossed, so
				swap(leftPtr, rightPtr);    // swap elements
		}  // end while(true)
		swap(leftPtr, right);

		int midindex = theArray.length / 2; // 中间位置

		if (leftPtr == midindex) {
			return leftPtr;
		} else if (leftPtr > midindex) {
			return findMedian(left, leftPtr - 1);
		} else {
			return findMedian(leftPtr + 1, right);
		}
	}

	// =============================================================
	// 编程作业 7.3
	public long median() {
		return theArray[findMedian(0, theArray.length - 1)];
	}

	// =============================================================
	// 编程作业 7.4
	public int findIndex(int left, int right, int index) {
		int leftPtr = left - 1;           // right of first elem
		int rightPtr = right;         	  // left of pivot
		long pivot = theArray[right];
		while (true) {
			while (leftPtr < right &&       // find bigger item
					theArray[++leftPtr] < pivot)
				;  // (nop)

			while (rightPtr > left &&       // find smaller item
					theArray[--rightPtr] > pivot)
				;  // (nop)
			if (leftPtr >= rightPtr)        // if pointers cross,
				break;                      // partition done
			else
				// not crossed, so
				swap(leftPtr, rightPtr);    // swap elements
		}  // end while(true)
		swap(leftPtr, right);

		if (leftPtr == index) {
			return leftPtr;
		} else if (leftPtr > index) {
			return findIndex(left, leftPtr - 1, index);
		} else {
			return findIndex(leftPtr + 1, right, index);
		}
	}

	// =============================================================
	public long findKth(int k) {
		if (k < 1 || k > theArray.length) {
			return -1;
		}
		return theArray[findIndex(0, theArray.length - 1, k - 1)];
	}

	// =============================================================
	// --------------------------

	public void swap(int dex1, int dex2)  // swap two elements
	{
		long temp;
		temp = theArray[dex1];             // A into temp
		theArray[dex1] = theArray[dex2];   // B into A
		theArray[dex2] = temp;             // temp into B
	}  // end swap()
		// --------------------------
}  // end class ArrayPar
// //////////////////////////////////////////////////////////////

public class partition {
	public static void main(String[] args) {
		int maxSize = 16;             // array size
		ArrayPar arr;                 // reference to array
		arr = new ArrayPar(maxSize);  // create the array

		for (int j = 0; j < maxSize; j++)  // fill array with
		{                          // random numbers
			long n = (int) (java.lang.Math.random() * 199);
			arr.insert(n);
		}
		arr.display();                // display unsorted array

		// long pivot = 99; // pivot value
		// System.out.print("Pivot is " + pivot);
		// int size = arr.size();
		// // partition array
		// int partDex = arr.partitionIt(0, size-1, pivot);
		//
		// System.out.println(", Partition is at index " + partDex);
		// arr.display(); // display partitioned array

		// ===================================================
		// 编程作业 7.1
		// int size = arr.size();
		// int partDex = arr.partitionIt(0, size - 1);
		// System.out.println("Pation is at index " + partDex);
		// arr.display();
		// ====================================================
		// 编程作业 7.3
		// System.out.println("中间值是:" + arr.median());
		// arr.display();
		// ===================================================
		// 编程作业 7.4
		System.out.println("第1小的值是:" + arr.findKth(1));
		arr.display();
		// ===================================================
	}  // end main()
}  // end class PartitionApp
// //////////////////////////////////////////////////////////////

package chap07;

class Link {
	public long dData; // data item
	public Link next; // next link in list

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

	public Link(long dd) // constructor
	{
		dData = dd;
	}

	// -------------------------
	public void displayLink() // display this link
	{
		System.out.print(dData + " ");
	}
} // end class Link

class CircleList {
	private Link current;
	private int nItems;

	public CircleList() {
		current = null;
	}

	public void insert(long value) {
		Link link = new Link(value);
		if (current == null) {
			current = link;
			link.next = link;
		} else {
			link.next = current.next;
			current.next = link;
			current = link;// 插入元素,current要移动要新元素
		}
		nItems++;
	}

	public long remove() {
		// list为空是没有考虑,在调用remove之前应该判断是否为空
		long temp = current.next.dData;// 删掉current的下一个元素
		if (current.next == current) { // 只有一个元素时
			current = null;
		} else {
			current.next = current.next.next;
		}
		nItems--;
		return temp;
	}

	public long peek() { // 返回最早插入的元素
		// 调用前要判断是否为空
		return current.next.dData;
	}

	public Link find(long value) {
		Link temp = current; // 保存原来的位置
		Link result = null;
		if (current == null) {
			return result;
		}
		do {
			step(); // 从current的下一个元素开始比较
			if (current.dData == value) {
				result = current;

				current = temp; // 还原current到原来的位置,这样就不会打乱插入的顺序,current指向最后插入的元素
				return result;
			}
		} while (current != temp); // current到达原来的位置,一周循环结束
		return result;
	}

	// 往下移一步
	public void step() { // 调用step()方法后,顺序会被打乱
		if (current != null) {
			current = current.next;
		}
	}

	public void display() {
		if (current != null) {
			Link temp = current;
			do {
				step(); // 从current的一下个开始显示
				System.out.print(current.dData + " ");
			} while (current != temp);
		}
		System.out.println();
	}

	public boolean isEmpty() {
		return current == null;
	}

	public int size() {
		return nItems;
	}
}

// =============================================================================
// 编程作业 7.5
// 基数排序算法
// 方法一
public class RadixSort {
	// ==============================================
	// 基数排序算法
	// ==============================================
	// 过程如下:
	// 初数组 8 12 22 15 20 7 25 18 212 基数为10
	// 首先按个位排序
	// 结果是 (20)(12 22 212)(15 25)(7)(8 18)
	// 然后按十位排序
	// 结果是 (7 8) (12 212 15 18) (20 22 25)
	// 然后按百位排序
	// 结果是 (7 8 12 15 18 20 22 25) 212
	// 排序结束
	// ==============================================
	// 此方法用链表暂存元素
	// ==============================================
	private static void radixSort(long[] array, int radix, int distance) {
		// array 为待排序数组
		// radix 代表基数
		// distance 代表排序元素的位数 //大于或等于最大的元素的位数
		int length = array.length;
		CircleList[] temp = new CircleList[radix];// 用于暂存元素
		for (int x = 0; x < radix; x++) { // 初始化数组
			temp[x] = new CircleList();
		}
		int divide = 1;

		for (int i = 0; i < distance; i++) {
			// 个人觉的运用基数排序实现基数排序的重点在下面这些代码
			for (int j = 0; j < length; j++) { // 按各元素相应位上的数字分组
				int tempindex = (int) (array[j] / divide) % radix;
				temp[tempindex].insert(array[j]);
			}
			int l = 0;
			for (int k = 0; k < temp.length; k++) { // 把分好组的元素复制回原数组
				while (!temp[k].isEmpty()) {
					array[l++] = temp[k].remove();
				}
			}
			divide = divide * radix;
		}
	}

	public static void main(String[] args) {
		long[] array = { 3, 2, 3, 2, 5, 333, 45566, 2345678, 78, 990, 12, 432, 56 };
		radixSort(array, 10, 7);
		for (int i = 0; i < array.length; i++) {
			System.out.print("  " + array[i]);
		}
	}
}
// =============================================================================