快速排序
1,基本思想:
随机找出一个数(通常就拿数组第一个数据就行),把它插入一个位置,使得它左边的数都比它小,它右边的数据都比它大,这样就将一个数组分成了两个子数组,然后再按照同样的方法把子数组再分成更小的子数组,直到不能分解为止。 它也是分治思想的一个经典实验(归并排序也是)。
2,算法
- public class QuickSort{
- public static void quickSort(Comparable[] a){
- //StdRandom.shuffle(a);//将数组a顺序打乱,消除对输入的依赖,这是《算法第四版》作者写好的静态函数,
- quickSort(a, 0, a.length-1);
- }
- public static void quickSort(Comparable[] a, int lo, int hi){
- if(hi <= lo) //跳出递归的条件,相当于不能再分解了
- return;
- int j = partition(a, lo, hi); //切分(将a[lo]插入到数组中合适的位置:左边比他小,右边比它大,这样就将数组切分成两部分)
- quickSort(a, lo, j-1); //将左半部分a[lo...j-1]排序
- quickSort(a, j+1, hi); //将右半部分a[j+1...hi]排序
- }
- private static int partition(Comparable[] a, int lo, int hi){
- //将数组切分为a[lo...i-1]、a[i] 和a[i+1...hi];
- int i = lo, j = hi + 1; //左右扫描的指针,j=hi+1,很大的程度上是为了下面写--j,
- Comparable v = a[lo]; //把要用来切分的元素保留
- while(true){ // 扫描左右检查扫描是否结束并交换元素
- while(less(a[++i], v))//两种条件会跳出while循环,直到在左侧找到比v大的,或i指针已经走到头了(i==hi),++i的原因:v是从lo开始的,满足less()
- if(i == hi) break;//不过这两个判断越界的测试条件是多余的,可以去掉,因为本身i,j就是从两端走过去的,不等走到头就
- while(less(v,a[--j]));
- if(j == lo) break;
- if(i >= j) break; //i和j碰上了,那就跳出整个循环,
- exch(a,i,j); //如果上两个while都跳出,说明i,j停在了a[i]>v ,a[j]<v处,所以将二者交换就可以了,然后i和j继续向中间靠拢
- }
- exch(a, lo, j); //将 v = a[j]放入正确的位置,当两个指针相遇时,交换a[lo]和a[j],这样切分的值就留在a[j]中了,初始的a[lo]找到了正确位置
- return j; //a[lo...j-1] <= a[j] <= a[j+1...hi]达成
- }
- }
排序方法 | 时间复杂度 | 空间复杂度 | 稳定性 | 复杂性 | ||
平均情况 | 最坏情况 | 最好情况 | ||||
快速排序 | O(nlog2n) | O(n2) | O(nlog2n) | O(log2n) | 不稳定 | 较复杂 |
冒泡排序
(1)基本思想
冒泡排序的基本思想就是:从无序序列头部开始,进行两两比较,根据大小交换位置,直到最后将最大(小)的数据元素交换到了无序队列的队尾,从而成为有序序列的一部分;下一次继续这个过程,直到所有数据元素都排好序。
算法的核心在于每次通过两两比较交换位置,选出剩余无序序列里最大(小)的数据元素放到队尾。
(2)运行过程
冒泡排序算法的运作如下:
1、比较相邻的元素。如果第一个比第二个大(小),就交换他们两个。
2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大(小)的数。
3、针对所有的元素重复以上的步骤,除了最后已经选出的元素(有序)。
4、持续每次对越来越少的元素(无序元素)重复上面的步骤,直到没有任何一对数字需要比较,则序列最终有序。
算法:
- public static void bubble_sort(int[] arr) {
- int i, j, temp, len = arr.length;
- for (i = 0; i < len - 1; i++)
- for (j = 0; j < len - 1 - i; j++)
- if (arr[j] > arr[j + 1]) {
- temp = arr[j];
- arr[j] = arr[j + 1];
- arr[j + 1] = temp;
- }
- }
二分查找
二分查找算法:是一种在有序数组中查找某一特定元素的搜索算法。
二分查找思想:搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组 为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为Ο(logn)。、
二分查找算法要求:1>必须采用顺序存储结构;2>必须按关键字大小有序排列
算法实现:
- #include <iostream>
- using namespace std;
- //二分查找: 递归实现
- int binarySearch(int a[],int low,int high,int key)
- {
- int mid=low+(high-low)/2;
- if(low>high)
- return -1;
- else{
- if(a[mid]==key)
- return mid;
- else if(a[mid]>key)
- return binarySearch(a,low,mid-1,key);
- else
- return binarySearch(a,mid+1,high,key);
- }
- }
- //二分查找:非递归方法实现
- int binarySearch(int a[],int n,int key)
- {
- int low=0,high=n-1;
- int mid;
- while(low<=high)
- {
- mid=(low+high)/2;
- if(key==a[mid])
- return mid;
- else if(key<a[mid])
- high=mid-1;
- else
- low=mid+1;
- }
- return -1;
- }
- int main()
- {
- int a[8]={1,3,4,5,6,7,9,10};
- int index=0;
- // index=binarySerach(a,0,8,3);
- index=binarySearch(a,8,3);
- cout<<"下表索引:"<<index<<endl<<"输出要查找的值:"<<a[index]<<endl;
- return 0;
- }
二分查找法的缺陷:数组必须有序
回文判断
给定一个字符串,如何判断这个字符串是否是回文串?
所谓回文串,是指正读和反读都一样的字符串,如madam、我爱我等。
解决上述问题,有两种方法可供参考:
(1)从字符串两头往中间扫;
(2)从字符串中间往两头扫。
具体代码如下:
package com.liuzhen.string_1; import java.util.Scanner; public class StringPalindrome { //方法1:两头往中间扫 public boolean IsPalindrome1(String A){ char[] arrayA = A.toCharArray(); int top = 0; int end = arrayA.length-1; if(A.equals("") || A.equals(null)) //非法输入 return false; while(top < end){ if(arrayA[top++] != arrayA[end--]) return false; } return true; } //方法2:中间往两头扫 public boolean IsPalindrome2(String A){ char[] arrayA = A.toCharArray(); int lenA = arrayA.length; int mid = lenA/2; int front; //前半部分 int back; //后半部分 if(lenA % 2 == 0){ //当字符串长度为偶数时 front = mid-1; back = mid; } else{ front = mid -1; back = mid + 1; } if(A.equals("") || A.equals(null)) return false; while(front >= 0 && back < lenA){ if(arrayA[front--] != arrayA[back++]) return false; } return true; } public static void main(String[] args){ StringPalindrome test = new StringPalindrome(); Scanner in = new Scanner(System.in); System.out.println("请输入一个字符串:"); String A = in.nextLine(); if(test.IsPalindrome1(A)) System.out.println("使用方法1判断结果为,输入字符串是回文字符串"); else System.out.println("使用方法1判断结果为,输入字符串不是回文字符串"); if(test.IsPalindrome2(A)) System.out.println("使用方法2判断结果为,输入字符串是回文字符串"); else System.out.println("使用方法2判断结果为,输入字符串不是回文字符串"); } }
运行结果:
请输入一个字符串:
我爱我
使用方法1判断结果为,输入字符串是回文字符串
使用方法2判断结果为,输入字符串是回文字符串
请输入一个字符串:
我爱你
使用方法1判断结果为,输入字符串不是回文字符串
使用方法2判断结果为,输入字符串不是回文字符串
请输入一个字符串:
abba
使用方法1判断结果为,输入字符串是回文字符串
使用方法2判断结果为,输入字符串是回文字符串
链表倒序
- /**
- * java 实现单链表的逆序
- * @author Administrator
- *
- */
- public class SingleLinkedReverse {
- class Node{
- int data;
- Node next;
- public Node(int data){
- this.data = data;
- }
- }
- public static void main(String[] args) {
- SingleLinkedReverse slr = new SingleLinkedReverse();
- Node head, tail;
- head = tail = slr.new Node(0);
- for(int i=1; i<10; i++){
- Node p = slr.new Node(i);
- tail.next = p;
- tail = p;
- }
- tail = head;
- while(tail != null){
- System.out.print(tail.data+" ");
- tail = tail.next;
- }
- head = reverse(head);
- System.out.println(" ");
- while(head != null){
- System.out.print(head.data+" ");
- head = head.next;
- }
- }
- private static Node reverse(Node head) {
- Node p1,p2 = null;
- p1 = head;
- while(head.next != null){
- p2 = head.next;
- head.next = p2.next;
- p2.next = p1;
- p1 = p2; //重点代码
- }
- return p2;
- }
- }
测试结果:
0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0