﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-飞艳小屋-文章分类-算法数据结构</title><link>http://www.blogjava.net/songfei/category/5001.html</link><description>欢迎艳儿的加入</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 17:11:43 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 17:11:43 GMT</pubDate><ttl>60</ttl><item><title>排序算法</title><link>http://www.blogjava.net/songfei/articles/50435.html</link><dc:creator>天外飞仙</dc:creator><author>天外飞仙</author><pubDate>Mon, 05 Jun 2006 02:24:00 GMT</pubDate><guid>http://www.blogjava.net/songfei/articles/50435.html</guid><wfw:comment>http://www.blogjava.net/songfei/comments/50435.html</wfw:comment><comments>http://www.blogjava.net/songfei/articles/50435.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/songfei/comments/commentRss/50435.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/songfei/services/trackbacks/50435.html</trackback:ping><description><![CDATA[
		<p>public class Sort { <br /><br />  public void swap(int a[], int i, int j) { <br />    int tmp = a[i]; <br />    a[i] = a[j]; <br />    a[j] = tmp; <br />  } <br /><br />  public int partition(int a[], int low, int high) { <br />    int pivot, p_pos, i; <br />    p_pos = low; <br />    pivot = a[p_pos]; <br />    for (i = low + 1; i &lt;= high; i++) { <br />      if (a[i] &gt; pivot) { <br />        p_pos++; <br />        swap(a, p_pos, i); <br />      } <br />    } <br />    swap(a, low, p_pos); <br />    return p_pos; <br />  } <br /><br />  public void quicksort(int a[], int low, int high) { <br />    int pivot; <br />    if (low &lt; high) { <br />      pivot = partition(a, low, high); <br />      quicksort(a, low, pivot - 1); <br />      quicksort(a, pivot + 1, high); <br />    } <br /><br />  } <br /><br />  public static void main(String args[]) { <br />    int vec[] = new int[] { 37, 47, 23, -5, 19, 56 }; <br />    int temp; <br />    //选择排序法(Selection Sort) <br />    long begin = System.currentTimeMillis(); <br />    for (int k = 0; k &lt; 1000000; k++) { <br />      for (int i = 0; i &lt; vec.length; i++) { <br />        for (int j = i; j &lt; vec.length; j++) { <br />          if (vec[j] &gt; vec[i]) { <br />            temp = vec[i]; <br />            vec[i] = vec[j]; <br />            vec[j] = temp; <br />          } <br />        } <br /><br />      } <br />    } <br />    long end = System.currentTimeMillis(); <br />    System.out.println("选择法用时为：" + (end - begin)); <br />    //打印排序好的结果 <br />    for (int i = 0; i &lt; vec.length; i++) { <br />      System.out.println(vec[i]); <br />    } <br />    //  冒泡排序法(Bubble Sort) <br />    begin = System.currentTimeMillis(); <br />    for (int k = 0; k &lt; 1000000; k++) { <br />      for (int i = 0; i &lt; vec.length; i++) { <br />        for (int j = i; j &lt; vec.length - 1; j++) { <br />          if (vec[j + 1] &gt; vec[j]) { <br />            temp = vec[j + 1]; <br />            vec[j + 1] = vec[j]; <br />            vec[j] = temp; <br />          } <br />        } <br /><br />      } <br />    } <br />    end = System.currentTimeMillis(); <br />    System.out.println("冒泡法用时为：" + (end - begin)); <br />    //打印排序好的结果 <br />    for (int i = 0; i &lt; vec.length; i++) { <br />      System.out.println(vec[i]); <br />    } <br /><br />    //插入排序法(Insertion Sort) <br />    begin = System.currentTimeMillis(); <br />    for (int k = 0; k &lt; 1000000; k++) { <br />      for (int i = 1; i &lt; vec.length; i++) { <br />        int j = i; <br />        while (vec[j - 1] &lt; vec[i]) { <br />          vec[j] = vec[j - 1]; <br />          j--; <br />          if (j &lt;= 0) { <br />            break; <br />          } <br />        } <br />        vec[j] = vec[i]; <br />      } <br />    } <br />    end = System.currentTimeMillis(); <br />    System.out.println("插入法用时为：" + (end - begin)); <br />    //打印排序好的结果 <br />    for (int i = 0; i &lt; vec.length; i++) { <br />      System.out.println(vec[i]); <br />    } <br /><br />    //快速排序法(Quick Sort) <br /><br />    Sort s = new Sort(); <br />    begin = System.currentTimeMillis(); <br />    for (int k = 0; k &lt; 1000000; k++) { <br />      s.quicksort(vec, 0, 5); <br />    } <br />    end = System.currentTimeMillis(); <br />    System.out.println("快速法用时为：" + (end - begin)); <br />    //打印排序好的结果 <br />    for (int i = 0; i &lt; vec.length; i++) { <br />      System.out.println(vec[i]); <br />    } <br />  } <br /><br />} <br /></p>
<img src ="http://www.blogjava.net/songfei/aggbug/50435.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/songfei/" target="_blank">天外飞仙</a> 2006-06-05 10:24 <a href="http://www.blogjava.net/songfei/articles/50435.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用Java语言实现的各种排序</title><link>http://www.blogjava.net/songfei/articles/38095.html</link><dc:creator>天外飞仙</dc:creator><author>天外飞仙</author><pubDate>Wed, 29 Mar 2006 09:30:00 GMT</pubDate><guid>http://www.blogjava.net/songfei/articles/38095.html</guid><wfw:comment>http://www.blogjava.net/songfei/comments/38095.html</wfw:comment><comments>http://www.blogjava.net/songfei/articles/38095.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/songfei/comments/commentRss/38095.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/songfei/services/trackbacks/38095.html</trackback:ping><description><![CDATA[用Java语言实现的各种排序，包括插入排序、冒泡排序、选择排序、Shell排序、快速排序、归并排序、堆排序、SortUtil等。
<p clear="both">插入排序：</p><p class="code">package org.rut.util.algorithm.support;<br /><br />import org.rut.util.algorithm.SortUtil;<br />/**<br /> * @author treeroot<br /> * @since 2006-2-2<br /> * @version 1.0<br /> */<br />public class InsertSort implements SortUtil.Sort{<br /><br />    /* (non-Javadoc)<br />     * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[])<br />     */<br />    public void sort(int[] data) {<br />        int temp;<br />        for(int i=1;i&lt;data.length;i++){<br />            for(int j=i;(j&gt;0)&amp;&amp;(data[j]&lt;data[j-1]);j--){<br />                SortUtil.swap(data,j,j-1);<br />            }<br />        }        <br />    }<br /><br />}</p><p>冒泡排序：</p><p class="code">package org.rut.util.algorithm.support;<br /><br />import org.rut.util.algorithm.SortUtil;<br /><br />/**<br /> * @author treeroot<br /> * @since 2006-2-2<br /> * @version 1.0<br /> */<br />public class BubbleSort implements SortUtil.Sort{<br /><br />    /* (non-Javadoc)<br />     * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[])<br />     */<br />    public void sort(int[] data) {<br />        int temp;<br />        for(int i=0;i&lt;data.length;i++){<br />            for(int j=data.length-1;j&gt;i;j--){<br />                if(data[j]&lt;data[j-1]){<br />                    SortUtil.swap(data,j,j-1);<br />                }<br />            }<br />        }<br />    }<br /><br />}</p><p></p><table cellspacing="0" cellpadding="6" width="100%" border="0"><tbody><tr><td><p>选择排序：</p><p class="code">package org.rut.util.algorithm.support;<br /><br />import org.rut.util.algorithm.SortUtil;<br /><br />/**<br /> * @author treeroot<br /> * @since 2006-2-2<br /> * @version 1.0<br /> */<br />public class SelectionSort implements SortUtil.Sort {<br /><br />    /*<br />     * (non-Javadoc)<br />     * <br />     * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[])<br />     */<br />    public void sort(int[] data) {<br />        int temp;<br />        for (int i = 0; i &lt; data.length; i++) {<br />            int lowIndex = i;<br />            for (int j = data.length - 1; j &gt; i; j--) {<br />                if (data[j] &lt; data[lowIndex]) {<br />                    lowIndex = j;<br />                }<br />            }<br />            SortUtil.swap(data,i,lowIndex);<br />        }<br />    }<br /><br />}</p><p>Shell排序：</p><p class="code">package org.rut.util.algorithm.support;<br /><br />import org.rut.util.algorithm.SortUtil;<br /><br />/**<br /> * @author treeroot<br /> * @since 2006-2-2<br /> * @version 1.0<br /> */<br />public class ShellSort implements SortUtil.Sort{<br /><br />    /* (non-Javadoc)<br />     * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[])<br />     */<br />    public void sort(int[] data) {<br />        for(int i=data.length/2;i&gt;2;i/=2){<br />            for(int j=0;j&lt;i;j++){<br />                insertSort(data,j,i);<br />            }<br />        }<br />        insertSort(data,0,1);<br />    }<br /><br />    /**<br />     * @param data<br />     * @param j<br />     * @param i<br />     */<br />    private void insertSort(int[] data, int start, int inc) {<br />        int temp;<br />        for(int i=start+inc;i&lt;data.length;i+=inc){<br />            for(int j=i;(j&gt;=inc)&amp;&amp;(data[j]&lt;data[j-inc]);j-=inc){<br />                SortUtil.swap(data,j,j-inc);<br />            }<br />        }<br />    }<br /><br />}</p><p></p><table cellspacing="0" cellpadding="6" width="100%" border="0"><tbody><tr><td></td></tr></tbody></table><table cellspacing="0" cellpadding="0" width="98%" align="center" border="0"><tbody><tr><td class="article" width="100%" height="62"><p></p><p>快速排序：</p><p class="code">package org.rut.util.algorithm.support;<br /><br />import org.rut.util.algorithm.SortUtil;<br /><br />/**<br /> * @author treeroot<br /> * @since 2006-2-2<br /> * @version 1.0<br /> */<br />public class QuickSort implements SortUtil.Sort{<br /><br />    /* (non-Javadoc)<br />     * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[])<br />     */<br />    public void sort(int[] data) {<br />        quickSort(data,0,data.length-1);        <br />    }<br />    private void quickSort(int[] data,int i,int j){<br />        int pivotIndex=(i+j)/2;<br />        //swap<br />        SortUtil.swap(data,pivotIndex,j);<br />        <br />        int k=partition(data,i-1,j,data[j]);<br />        SortUtil.swap(data,k,j);<br />        if((k-i)&gt;1) quickSort(data,i,k-1);<br />        if((j-k)&gt;1) quickSort(data,k+1,j);<br />        <br />    }<br />    /**<br />     * @param data<br />     * @param i<br />     * @param j<br />     * @return<br />     */<br />    private int partition(int[] data, int l, int r,int pivot) {<br />        do{<br />           while(data[++l]&lt;pivot);<br />           while((r!=0)&amp;&amp;data[--r]&gt;pivot);<br />           SortUtil.swap(data,l,r);<br />        }<br />        while(l&lt;r);<br />        SortUtil.swap(data,l,r);        <br />        return l;<br />    }<br /><br />}</p><p>改进后的快速排序：</p><p class="code">package org.rut.util.algorithm.support;<br /><br />import org.rut.util.algorithm.SortUtil;<br /><br />/**<br /> * @author treeroot<br /> * @since 2006-2-2<br /> * @version 1.0<br /> */<br />public class ImprovedQuickSort implements SortUtil.Sort {<br /><br />    private static int MAX_STACK_SIZE=4096;<br />    private static int THRESHOLD=10;<br />    /* (non-Javadoc)<br />     * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[])<br />     */<br />    public void sort(int[] data) {<br />        int[] stack=new int[MAX_STACK_SIZE];<br />        <br />        int top=-1;<br />        int pivot;<br />        int pivotIndex,l,r;<br />        <br />        stack[++top]=0;<br />        stack[++top]=data.length-1;<br />        <br />        while(top&gt;0){<br />            int j=stack[top--];<br />            int i=stack[top--];<br />            <br />            pivotIndex=(i+j)/2;<br />            pivot=data[pivotIndex];<br />            <br />            SortUtil.swap(data,pivotIndex,j);<br />            <br />            //partition<br />            l=i-1;<br />            r=j;<br />            do{<br />                while(data[++l]&lt;pivot);<br />                while((r!=0)&amp;&amp;(data[--r]&gt;pivot));<br />                SortUtil.swap(data,l,r);<br />            }<br />            while(l&lt;r);<br />            SortUtil.swap(data,l,r);<br />            SortUtil.swap(data,l,j);<br />            <br />            if((l-i)&gt;THRESHOLD){<br />                stack[++top]=i;<br />                stack[++top]=l-1;<br />            }<br />            if((j-l)&gt;THRESHOLD){<br />                stack[++top]=l+1;<br />                stack[++top]=j;<br />            }<br />            <br />        }<br />        //new InsertSort().sort(data);<br />        insertSort(data);<br />    }<br />    /**<br />     * @param data<br />     */<br />    private void insertSort(int[] data) {<br />        int temp;<br />        for(int i=1;i&lt;data.length;i++){<br />            for(int j=i;(j&gt;0)&amp;&amp;(data[j]&lt;data[j-1]);j--){<br />                SortUtil.swap(data,j,j-1);<br />            }<br />        }       <br />    }<br /><br />}</p></td></tr></tbody></table><p>归并排序：</p><p class="code">package org.rut.util.algorithm.support;<br /><br />import org.rut.util.algorithm.SortUtil;<br /><br />/**<br /> * @author treeroot<br /> * @since 2006-2-2<br /> * @version 1.0<br /> */<br />public class MergeSort implements SortUtil.Sort{<br /><br />    /* (non-Javadoc)<br />     * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[])<br />     */<br />    public void sort(int[] data) {<br />        int[] temp=new int[data.length];<br />        mergeSort(data,temp,0,data.length-1);<br />    }<br />    <br />    private void mergeSort(int[] data,int[] temp,int l,int r){<br />        int mid=(l+r)/2;<br />        if(l==r) return ;<br />        mergeSort(data,temp,l,mid);<br />        mergeSort(data,temp,mid+1,r);<br />        for(int i=l;i&lt;=r;i++){<br />            temp[i]=data[i];<br />        }<br />        int i1=l;<br />        int i2=mid+1;<br />        for(int cur=l;cur&lt;=r;cur++){<br />            if(i1==mid+1)<br />                data[cur]=temp[i2++];<br />            else if(i2&gt;r)<br />                data[cur]=temp[i1++];<br />            else if(temp[i1]&lt;temp[i2])<br />                data[cur]=temp[i1++];<br />            else<br />                data[cur]=temp[i2++];            <br />        }<br />    }<br /><br />}</p><p>改进后的归并排序:</p><p class="code">package org.rut.util.algorithm.support;<br /><br />import org.rut.util.algorithm.SortUtil;<br /><br />/**<br /> * @author treeroot<br /> * @since 2006-2-2<br /> * @version 1.0<br /> */<br />public class ImprovedMergeSort implements SortUtil.Sort {<br /><br />    private static final int THRESHOLD = 10;<br /><br />    /*<br />     * (non-Javadoc)<br />     * <br />     * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[])<br />     */<br />    public void sort(int[] data) {<br />        int[] temp=new int[data.length];<br />        mergeSort(data,temp,0,data.length-1);<br />    }<br /><br />    private void mergeSort(int[] data, int[] temp, int l, int r) {<br />        int i, j, k;<br />        int mid = (l + r) / 2;<br />        if (l == r)<br />            return;<br />        if ((mid - l) &gt;= THRESHOLD)<br />            mergeSort(data, temp, l, mid);<br />        else<br />            insertSort(data, l, mid - l + 1);<br />        if ((r - mid) &gt; THRESHOLD)<br />            mergeSort(data, temp, mid + 1, r);<br />        else<br />            insertSort(data, mid + 1, r - mid);<br /><br />        for (i = l; i &lt;= mid; i++) {<br />            temp[i] = data[i];<br />        }<br />        for (j = 1; j &lt;= r - mid; j++) {<br />            temp[r - j + 1] = data[j + mid];<br />        }<br />        int a = temp[l];<br />        int b = temp[r];<br />        for (i = l, j = r, k = l; k &lt;= r; k++) {<br />            if (a &lt; b) {<br />                data[k] = temp[i++];<br />                a = temp[i];<br />            } else {<br />                data[k] = temp[j--];<br />                b = temp[j];<br />            }<br />        }<br />    }<br /><br />    /**<br />     * @param data<br />     * @param l<br />     * @param i<br />     */<br />    private void insertSort(int[] data, int start, int len) {<br />        for(int i=start+1;i&lt;start+len;i++){<br />            for(int j=i;(j&gt;start) &amp;&amp; data[j]&lt;data[j-1];j--){<br />                SortUtil.swap(data,j,j-1);<br />            }<br />        }<br />    }</p><p>}<br /><br />package org.rut.util.algorithm.support;<br /><br />import org.rut.util.algorithm.SortUtil;<br /><br />/**<br /> * @author treeroot<br /> * @since 2006-2-2<br /> * @version 1.0<br /> */<br />public class HeapSort implements SortUtil.Sort{<br /><br />    /* (non-Javadoc)<br />     * @see org.rut.util.algorithm.SortUtil.Sort#sort(int[])<br />     */<br />    public void sort(int[] data) {<br />        MaxHeap h=new MaxHeap();<br />        h.init(data);<br />        for(int i=0;i&lt;data.length;i++)<br />            h.remove();<br />        System.arraycopy(h.queue,1,data,0,data.length);<br />    }<br /><br />     private static class MaxHeap{         <br />        <br />        void init(int[] data){<br />            this.queue=new int[data.length+1];<br />            for(int i=0;i&lt;data.length;i++){<br />                queue[++size]=data[i];<br />                fixUp(size);<br />            }<br />        }<br />         <br />        private int size=0;<br /><br />        private int[] queue;<br />                <br />        public int get() {<br />            return queue[1];<br />        }<br /><br />        public void remove() {<br />            SortUtil.swap(queue,1,size--);<br />            fixDown(1);<br />        }<br />        //fixdown<br />        private void fixDown(int k) {<br />            int j;<br />            while ((j = k &lt;&lt; 1) &lt;= size) {<br />                if (j &lt; size &amp;&amp; queue[j]&lt;queue[j+1])<br />                    j++; <br />                if (queue[k]&gt;queue[j]) //不用交换<br />                    break;<br />                SortUtil.swap(queue,j,k);<br />                k = j;<br />            }<br />        }<br />        private void fixUp(int k) {<br />            while (k &gt; 1) {<br />                int j = k &gt;&gt; 1;<br />                if (queue[j]&gt;queue[k])<br />                    break;<br />                SortUtil.swap(queue,j,k);<br />                k = j;<br />            }<br />        }<br /><br />    }<br /><br />}<br /><br /></p><p>SortUtil：</p><p class="code">package org.rut.util.algorithm;<br /><br />import org.rut.util.algorithm.support.BubbleSort;<br />import org.rut.util.algorithm.support.HeapSort;<br />import org.rut.util.algorithm.support.ImprovedMergeSort;<br />import org.rut.util.algorithm.support.ImprovedQuickSort;<br />import org.rut.util.algorithm.support.InsertSort;<br />import org.rut.util.algorithm.support.MergeSort;<br />import org.rut.util.algorithm.support.QuickSort;<br />import org.rut.util.algorithm.support.SelectionSort;<br />import org.rut.util.algorithm.support.ShellSort;<br /><br />/**<br /> * @author treeroot<br /> * @since 2006-2-2<br /> * @version 1.0<br /> */<br />public class SortUtil {<br />    public final static int INSERT = 1;<br />    public final static int BUBBLE = 2;<br />    public final static int SELECTION = 3;<br />    public final static int SHELL = 4;<br />    public final static int QUICK = 5;<br />    public final static int IMPROVED_QUICK = 6;<br />    public final static int MERGE = 7;<br />    public final static int IMPROVED_MERGE = 8;<br />    public final static int HEAP = 9;<br /><br />    public static void sort(int[] data) {<br />        sort(data, IMPROVED_QUICK);<br />    }<br />    private static String[] name={<br />            "insert", "bubble", "selection", "shell", "quick", "improved_quick", "merge", "improved_merge", "heap"<br />    };<br />    <br />    private static Sort[] impl=new Sort[]{<br />            new InsertSort(),<br />            new BubbleSort(),<br />            new SelectionSort(),<br />            new ShellSort(),<br />            new QuickSort(),<br />            new ImprovedQuickSort(),<br />            new MergeSort(),<br />            new ImprovedMergeSort(),<br />            new HeapSort()<br />    };<br /><br />    public static String toString(int algorithm){<br />        return name[algorithm-1];<br />    }<br />    <br />    public static void sort(int[] data, int algorithm) {<br />        impl[algorithm-1].sort(data);<br />    }<br /><br />    public static interface Sort {<br />        public void sort(int[] data);<br />    }<br /><br />    public static void swap(int[] data, int i, int j) {<br />        int temp = data[i];<br />        data[i] = data[j];<br />        data[j] = temp;<br />    }<br />}</p></td></tr></tbody></table><img src ="http://www.blogjava.net/songfei/aggbug/38095.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/songfei/" target="_blank">天外飞仙</a> 2006-03-29 17:30 <a href="http://www.blogjava.net/songfei/articles/38095.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据结构</title><link>http://www.blogjava.net/songfei/articles/20262.html</link><dc:creator>天外飞仙</dc:creator><author>天外飞仙</author><pubDate>Thu, 17 Nov 2005 08:32:00 GMT</pubDate><guid>http://www.blogjava.net/songfei/articles/20262.html</guid><wfw:comment>http://www.blogjava.net/songfei/comments/20262.html</wfw:comment><comments>http://www.blogjava.net/songfei/articles/20262.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/songfei/comments/commentRss/20262.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/songfei/services/trackbacks/20262.html</trackback:ping><description><![CDATA[<P>各章节重点勾划：<BR>第0章　概述<BR>本章主要起到总领作用，为读者进行数据结构的学习进行了一些先期铺垫。大家主要注意以下几点：数据结构的基本概念，时间和空间复杂度的概念及度量方法，算法设计时的注意事项。本章考点不多，只要稍加注意理解即可。<BR><BR>第一章　线性表<BR>作为线性结构的开篇章节，线性表一章在线性结构的学习乃至整个数据结构学科的学习中，其作用都是不可低估的。在这一章，第一次系统性地引入链式存储的概念，链式存储概念将是整个数据结构学科的重中之重，无论哪一章都涉及到了这个概念。<BR><BR>总体来说，线性表一章可供考查的重要考点有以下几个方面：<BR><BR>1.线性表的相关基本概念，如：前驱、后继、表长、空表、首元结点，头结点，头指针等概念。<BR>2.线性表的结构特点，主要是指：除第一及最后一个元素外，每个结点都只有一个前趋和只有一个后继。<BR>3.线性表的顺序存储方式及其在具体语言环境下的两种不同实现：表空间的静态分配和动态分配。静态链表与顺序表的相似及不同之处。<BR>4.线性表的链式存储方式及以下几种常用链表的特点和运算：单链表、循环链表，双向链表，双向循环链表。其中，单链表的归并算法、循环链表的归并算法、双向链表及双向循环链表的插入和删除算法等都是较为常见的考查方式。此外，近年来在不少学校中还多次出现要求用递归算法实现单链表输出（可能是顺序也可能是倒序）的问题。<BR>在链表的小题型中，经常考到一些诸如：判表空的题。在不同的链表中，其判表空的方式是不一样的，请大家注意。<BR>5.线性表的顺序存储及链式存储情况下，其不同的优缺点比较，即其各自适用的场合。单链表中设置头指针、循环链表中设置尾指针而不设置头指针以及索引存储结构的各自好处。<BR><BR>第二章　栈与队列<BR>栈与队列，是很多学习DS的同学遇到第一只拦路虎，很多人从这一章开始坐晕车，一直晕到现在。所以，理解栈与队列，是走向DS高手的一条必由之路，。<BR><BR>学习此章前，你可以问一下自己是不是已经知道了以下几点：<BR><BR>1.栈、队列的定义及其相关数据结构的概念，包括：顺序栈，链栈，共享栈，循环队列，链队等。栈与队列存取数据（请注意包括：存和取两部分）的特点。<BR>2.递归算法。栈与递归的关系，以及借助栈将递归转向于非递归的经典算法：n!阶乘问题，fib数列问题，hanoi问题，背包问题，二叉树的递归和非递归遍历问题，图的深度遍历与栈的关系等。其中，涉及到树与图的问题，多半会在树与图的相关章节中进行考查。<BR>3.栈的应用：数值表达式的求解，括号的配对等的原理，只作原理性了解，具体要求考查此为题目的算法设计题不多。<BR>4.循环队列中判队空、队满条件，循环队列中入队与出队算法。<BR><BR>如果你已经对上面的几点了如指掌，栈与队列一章可以不看书了。注意，我说的是可以不看书，并不是可以不作题哦。<BR><BR>第三章　串<BR>经历了栈一章的痛苦煎熬后，终于迎来了串一章的柳暗花明。<BR><BR>串，在概念上是比较少的一个章节，也是最容易自学的章节之一，但正如每个过来人所了解的，KMP算法是这一章的重要关隘，突破此关隘后，走过去又是一马平川的大好DS山河了，呵呵。<BR><BR>串一章需要攻破的主要堡垒有：<BR><BR>1.串的基本概念，串与线性表的关系（串是其元素均为字符型数据的特殊线性表），空串与空格串的区别，串相等的条件<BR>2.串的基本操作，以及这些基本函数的使用，包括：取子串，串连接，串替换，求串长等等。运用串的基本操作去完成特定的算法是很多学校在基本操作上的考查重点。<BR>3.顺序串与链串及块链串的区别和联系，实现方式。<BR>4.KMP算法思想。KMP中next数组以及nextval数组的求法。明确传统模式匹配算法的不足，明确next数组需要改进之外。其中，理解算法是核心，会求数组是得分点。不用我多说，这一节内容是本章的重中之重。可能进行的考查方式是：求next和nextval数组值，根据求得的next或nextval数组值给出运用KMP算法进行匹配的匹配过程。<BR><BR><BR>第四章　数组与广义表<BR>学过程序语言的朋友，数组的概念我们已经不是第一次见到了，应该已经“一回生，二回熟”了，所以，在概念上，不会存在太大障碍。但作为考研课程来说，本章的考查重点可能与大学里的程序语言所关注的不太一样，下面会作介绍。<BR><BR>广义表的概念，是数据结构里第一次出现的。它是线性表或表元素的有限序列，构成该结构的每个子表或元素也是线性结构的，所以，这一章也归入线性结构中。<BR><BR>本章的考查重点有：<BR>1.多维数组中某数组元素的position求解。一般是给出数组元素的首元素地址和每个元素占用的地址空间并组给出多维数组的维数，然后要求你求出该数组中的某个元素所在的位置。<BR>2.明确按行存储和按列存储的区别和联系，并能够按照这两种不同的存储方式求解1中类型的题。<BR>3.将特殊矩阵中的元素按相应的换算方式存入数组中。这些矩阵包括：对称矩阵，三角矩阵，具有某种特点的稀疏矩阵等。熟悉稀疏矩阵的三种不同存储方式：三元组，带辅助行向量的二元组，十字链表存储。掌握将稀疏矩阵的三元组或二元组向十字链表进行转换的算法。<BR>4.广义表的概念，特别应该明确表头与表尾的定义。这一点，是理解整个广义表一节算法的基础。近来，在一些学校中，出现了这样一种题目类型：给出对某个广义表L若干个求了若干次的取头和取尾操作后的串值，要求求出原广义表L。大家要留意。<BR>5.与广义表有关的递归算法。由于广义表的定义就是递归的，所以，与广义表有关的算法也常是递归形式的。比如：求表深度，复制广义表等。这种题目，可以根据不同角度广义表的表现形式运用两种不同的方式解答：一是把一个广义表看作是表头和表尾两部分，分别对表头和表尾进行操作；二是把一个广义表看作是若干个子表，分别对每个子表进行操作。<BR><BR>第五章　树与二叉树<BR>从对线性结构的研究过度到对树形结构的研究，是数据结构课程学习的一次跃变，此次跃变完成的好坏，将直接关系到你到实际的考试中是否可以拿到高分，而这所有的一切，将最终影响你的专业课总分。所以，树这一章的重要性，已经不说自明了。<BR><BR>总体来说，树一章的知识点包括：<BR>二叉树的概念、性质和存储结构，二叉树遍历的三种算法（递归与非递归），在三种基本遍历算法的基础上实现二叉树的其它算法，线索二叉树的概念和线索化算法以及线索化后的查找算法，最优二叉树的概念、构成和应用，树的概念和存储形式，树与森林的遍历算法及其与二叉树遍历算法的联系，树与森林和二叉树的转换。<BR><BR>下面我们来看考试中对以上知识的主要考查方法：<BR>1.二叉树的概念、性质和存储结构<BR>考查方法可有：直接考查二叉树的定义，让你说明二叉树与普通双分支树的区别；考查满二叉树和完全二叉树的性质，普通二叉树的五个性质：第i层的最多结点数，深度为k的二叉树的最多结点数，n0=n2+1的性质，n个结点的完全二叉树的深度，顺序存储二叉树时孩子结点与父结点之间的换算关系（左为：2*i，右为：2*i+1）。<BR>二叉树的顺序存储和二叉链表存储的各自优缺点及适用场合，二叉树的三叉链表表示方法。<BR>2.二叉树的三种遍历算法<BR>这一知识点掌握的好坏，将直接关系到树一章的算法能否理解，进而关系到树一章的算法设计题能否顺利完成。二叉树的遍历算法有三种：先序，中序和后序。其划分的依据是视其每个算法中对根结点数据的访问顺序而定。不仅要熟练掌握三种遍历的递归算法，理解其执行的实际步骤，并且应该熟练掌握三种遍历的非递归算法。由于二叉树一章的很多算法，可以直接根据三种递归算法改造而来（比如：求叶子个数），所以，掌握了三种遍历的非递归算法后，对付诸如：“利用非递归算法求二叉树叶子个数”这样的题目就下笔如有神了。我会在另一篇系列文章（<IMG alt=::URL:: hspace=2 src="http://www.blogcn.com/images/aurl.gif" onload="function anonymous()&#13;&#10;{&#13;&#10;var image=new Image();image.src=this.src;if(image.width>0 &amp;&amp; image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}&#13;&#10;}" align=absBottom border=0><A href="http://bbs.kaoyan.com/ibbs.dll?bbsdisp?t_id=301583&amp;bp=2&amp;bt=0）里给出三种遍历的递归和非递归算法的背记版，到时请大家一定熟记。" target=_blank>http://bbs.kaoyan.com/ibbs.dll?bbsdisp?t_id=301583&amp;bp=2&amp;bt=0）里给出三种遍历的递归和非递归算法的背记版，到时请大家一定熟记。</A> <BR>3.可在三种遍历算法的基础上改造完成的其它二叉树算法：<BR>求叶子个数，求二叉树结点总数，求度为1或度为2的结点总数，复制二叉树，建立二叉树，交换左右子树，查找值为n的某个指定结点，删除值为n的某个指定结点，诸如此类等等等等。如果你可以熟练掌握二叉树的递归和非递归遍历算法，那么解决以上问题就是小菜一碟了。<BR>4.线索二叉树：<BR>线索二叉树的引出，是为避免如二叉树遍历时的递归求解。众所周知，递归虽然形式上比较好理解，但是消耗了大量的内存资源，如果递归层次一多，势必带来资源耗尽的危险，为了避免此类情况，线索二叉树便堂而皇之地出现了。对于线索二叉树，应该掌握：线索化的实质，三种线索化的算法，线索化后二叉树的遍历算法，基本线索二叉树的其它算法问题（如：查找某一类线索二叉树中指定结点的前驱或后继结点就是一类常考题）。<BR>5.最优二叉树（哈夫曼树）：<BR>最优二叉树是为了解决特定问题引出的特殊二叉树结构，它的前提是给二叉树的每条边赋予了权值，这样形成的二叉树按权相加之和是最小的。最优二叉树一节，直接考查算法源码的很少，一般是给你一组数据，要求你建立基于这组数据的最优二叉树，并求出其最小权值之和，此类题目不难，属送分题。<BR>6.树与森林：<BR>二叉树是一种特殊的树，这种特殊不仅仅在于其分支最多为2以及其它特征，一个最重要的特殊之处是在于：二叉树是有序的！即：二叉树的左右孩子是不可交换的，如果交换了就成了另外一棵二叉树，这样交换之后的二叉树与原二叉树我们认为是不相同的两棵二叉树。但是，对于普通的双分支树而言，不具有这种性质。<BR>树与森林的遍历，不像二叉树那样丰富，他们只有两种遍历算法：先根与后根（对于森林而言称作：先序与后序遍历）。在难度比较大的考试中，也有基于此二种算法的基础上再进行扩展要求你利用这两种算法设计其它算法的，但一般院校很少有这种考法，最多只是要求你根据先根或后根写出他们的遍历序列。此二者的先根与后根遍历与二叉树中的遍历算法是有对应关系的：先根遍历对应二叉树的先序遍历，而后根遍历对应二叉树的中序遍历。这一点成为很多学校的考点，考查的方式不一而足，有的直接考此句话，有的是先让你求解遍历序列然后回答这个问题。二叉树、树与森林之所以能有以上的对应关系，全拜二叉链表所赐。二叉树使用二叉链表分别存放他的左右孩子，树利用二叉链表存储孩子及兄弟（称孩子兄弟链表），而森林也是利用二叉链表存储孩子及兄弟。<BR><BR>树一章，处处是重点，道道是考题，大家务必个个过关。<BR><BR>第六章　图<BR>如果说，从线性结构向树形结构研究的转变，是数据结构学科对数据组织形式研究的一次升华，那么从树形结构的研究转到图形结构的研究，则进一步让我们看到了数据结构对于解决实际问题的重大推动作用。<BR><BR>图这一章的特点是：概念繁多，与离散数学中图的概念联系紧密，算法复杂，极易被考到，且容易出大题，尤其是名校，作为考研课程，如果不考查树与图两章的知识，几乎是不可想像的。<BR><BR>下面我们看一下图这一章的主要考点以及这些考点的考查方式：<BR>1.考查有关图的基本概念问题：<BR>这些概念是进行图一章学习的基础，这一章的概念包括：图的定义和特点，无向图，有向图，入度，出度，完全图，生成子图，路径长度，回路，（强）连通图，（强）连通分量等概念。与这些概念相联系的相关计算题也应该掌握。<BR>2.考查图的几种存储形式：<BR>图的存储形式包括：邻接矩阵，（逆）邻接表，十字链表及邻接多重表。在考查时，有的学校是给出一种存储形式，要求考生用算法或手写出与给定的结构相对应的该图的另一种存储形式。<BR>3.考查图的两种遍历算法：深度遍历和广度遍历<BR>深度遍历和广度遍历是图的两种基本的遍历算法，这两个算法对图一章的重要性等同于“先序、中序、后序遍历”对于二叉树一章的重要性。在考查时，图一章的算法设计题常常是基于这两种基本的遍历算法而设计的，比如：“求最长的最短路径问题”和“判断两顶点间是否存在长为K的简单路径问题”，就分别用到了广度遍历和深度遍历算法。<BR>4.生成树、最小生成树的概念以及最小生成树的构造：PRIM算法和KRUSKAL算法。<BR>考查时，一般不要求写出算法源码，而是要求根据这两种最小生成树的算法思想写出其构造过程及最终生成的最小生成树。<BR>5.拓扑排序问题：<BR>拓扑排序有两种方法，一是无前趋的顶点优先算法，二是无后继的顶点优先算法。换句话说，一种是“从前向后”的排序，一种是“从后向前”排。当然，后一种排序出来的结果是“逆拓扑有序”的。<BR>6.关键路径问题：<BR>这个问题是图一章的难点问题。理解关键路径的关键有三个方面：一是何谓关键路径，二是最早时间是什么意思、如何求，三是最晚时间是什么意思、如何求。简单地说，最早时间是通过“从前向后”的方法求的，而最晚时间是通过“从后向前”的方法求解的，并且，要想求最晚时间必须是在所有的最早时间都已经求出来之后才能进行。这个问题拿来直接考算法源码的不多，一般是要求按照书上的算法描述求解的过程和步骤。<BR>在实际设计关键路径的算法时，还应该注意以下这一点：采用邻接表的存储结构，求最早时间和最晚时间要采用不同的处理方法，即：在算法初始时，应该首先将所有顶点的最早时间全部置为0。关键路径问题是工程进度控制的重要方法，具有很强的实用性。<BR>7.最短路径问题：<BR>与关键路径问题并称为图一章的两只拦路虎。概念理解是比较容易的，关键是算法的理解。最短路径问题分为两种：一是求从某一点出发到其余各点的最短路径；二是求图中每一对顶点之间的最短路径。这个问题也具有非常实用的背景特色，一个典型的应该就是旅游景点及旅游路线的选择问题。解决第一个问题用DIJSKTRA算法，解决第二个问题用FLOYD算法。注意区分。<BR><BR>第七章　查找<BR>在不少数据结构的教材中，是把查找与排序放入高级数据结构中的。应该说，查找和排序两章是前面我们所学的知识的综合运用，用到了树、也用到了链表等知识，对这些数据结构某一方面的运用就构成了查找和排序。<BR><BR>现实生活中，search几乎无处不在，特别是现在的网络时代，万事离不开search，小到文档内文字的搜索，大到INTERNET上的搜索，search占据了我们上网的大部分时间。<BR><BR>在复习这一章的知识时，你需要先弄清楚以下几个概念：<BR>关键字、主关键字、次关键字的含义；静态查找与动态查找的含义及区别；平均查找长度ASL的概念及在各种查找算法中的计算方法和计算结果，特别是一些典型结构的ASL值，应该记住。<BR><BR>在DS的教材中，一般将search分为三类：1st，在顺序表上的查找；2nd，在树表上的查找；3rd，在哈希表上的查找。下面详细介绍其考查知识点及考查方式：<BR><BR>1.线性表上的查找：<BR>主要分为三种线性结构：顺序表，有序顺序表，索引顺序表。对于第一种，我们采用传统查找方法，逐个比较。对于及有序顺序表我们采用二分查找法。对于第三种索引结构，我们采用索引查找算法。考生需要注意这三种表下的ASL值以及三种算法的实现。其中，二分查找还要特别注意适用条件以及其递归实现方法。<BR>2.树表上的查找：<BR>这是本章的重点和难点。由于这一节介绍的内容是使用树表进行的查找，所以很容易与树一间的某些概念相混淆。本节内容与树一章的内容有联系，但也有很多不同，应注意规纳。树表主要分为以下几种：二叉排序树，平衡二叉树，B树，键树。其中，尤以前两种结构为重，也有部分名校偏爱考B树的。由于二叉排序树与平衡二叉树是一种特殊的二叉树，所以与二叉树的联系就更为紧密，二叉树一章学好了，这里也就不难了。<BR>二叉排序树，简言之，就是“左小右大”，它的中序遍历结果是一个递增的有序序列。平衡二叉树是二叉排序树的优化，其本质也是一种二叉排序树，只不过，平衡二叉树对左右子树的深度有了限定：深度之差的绝对值不得大于1。对于二叉排序树，“判断某棵二叉树是否二叉排序树”这一算法经常被考到，可用递归，也可以用非递归。平衡二叉树的建立也是一个常考点，但该知识点归根结底还是关注的平衡二叉树的四种调整算法，所以应该掌握平衡二叉树的四种调整算法，调整的一个参照是：调整前后的中序遍历结果相同。<BR>B树是二叉排序树的进一步改进，也可以把B树理解为三叉、四叉....排序树。除B树的查找算法外，应该特别注意一下B树的插入和删除算法。因为这两种算法涉及到B树结点的分裂和合并，是一个难点。B树是报考名校的同学应该关注的焦点之一。<BR>键树也称字符树，特别适用于查找英文单词的场合。一般不要求能完整描述算法源码，多是根据算法思想建立键树及描述其大致查找过程。<BR>3.基本哈希表的查找算法：<BR>哈希一词，是外来词，译自“hash”一词，意为：散列或杂凑的意思。哈希表查找的基本思想是：根据当前待查找数据的特征，以记录关键字为自变量，设计一个function，该函数对关键字进行转换后，其解释结果为待查的地址。基于哈希表的考查点有：哈希函数的设计，冲突解决方法的选择及冲突处理过程的描述。<BR><BR>第八章　内部排序<BR>内排是DS课程中最后一个重要的章节，建立在此章之上的考题可以有多种类型：填空，选择，判断乃至大型算法题。但是，归结到一点，就是考查你对书本上的各种排序算法及其思想以及其优缺点和性能指标（时间复杂度）能否了如指掌。<BR><BR>这一章，我们对重点的规纳将跟以上各章不同。我们将从以下几个侧面来对排序一章进行不同的规纳，以期能更全面的理解排序一章的总体结构及各种算法。<BR><BR>从排序算法的种类来分，本章主要阐述了以下几种排序方法：插入、选择、交换、归并、计数等五种排序方法。<BR><BR>其中，在插入排序中又可分为：直接插入、折半插入、2路插入、希尔排序。这几种插入排序算法的最根本的不同点，说到底就是根据什么规则寻找新元素的插入点。直接插入是依次寻找，折半插入是折半寻找。希尔排序，是通过控制每次参与排序的数的总范围“由小到大”的增量来实现排序效率提高的目的。<BR><BR>交换排序，又称冒泡排序，在交换排序的基础上改进又可以得到快速排序。快速排序的思想，一语以敝之：用中间数将待排数据组一分为二。快速排序，在处理的“问题规模”这个概念上，与希尔有点相反，快速排序，是先处理一个较大规模，然后逐渐把处理的规模降低，最终达到排序的目的。<BR><BR>选择排序，相对于前面几种排序算法来说，难度大一点。具体来说，它可以分为：简单选择、树选择、堆排。这三种方法的不同点是，根据什么规则选取最小的数。简单选择，是通过简单的数组遍历方案确定最小数；树选择，是通过“锦标赛”类似的思想，让两数相比，不断淘汰较大（小）者，最终选出最小（大）数；而堆排序，是利用堆这种数据结构的性质，通过堆元素的删除、调整等一系列操作将最小数选出放在堆顶。堆排序中的堆建立、堆调整是重要考点。树选择排序，也曾经在一些学校中的大型算法题中出现，请大家注意。<BR><BR>归并排序，故名思义，是通过“归并”这种操作完成排序的目的，既然是归并就必须是两者以上的数据集合才可能实现归并。所以，在归并排序中，关注最多的就是2路归并。算法思想比较简单，有一点，要铭记在心：归并排序是稳定排序。<BR><BR>基数排序，是一种很特别的排序方法，也正是由于它的特殊，所以，基数排序就比较适合于一些特别的场合，比如扑克牌排序问题等。基数排序，又分为两种：多关键字的排序（扑克牌排序），链式排序（整数排序）。基数排序的核心思想也是利用“基数空间”这个概念将问题规模规范、变小，并且，在排序的过程中，只要按照基排的思想，是不用进行关键字比较的，这样得出的最终序列就是一个有序序列。<BR><BR>本章各种排序算法的思想以及伪代码实现，及其时间复杂度都是必须掌握的，学习时要多注意规纳、总结、对比。此外，对于教材中的10.7节，要求必须熟记，在理解的基础上记忆，这一节几乎成为很多学校每年的必考点。<BR><BR>至此，数据结构所有章节的章节重点问题，我们已经规纳完毕，使用清华严版教材的同学，在复习的同时，可以参照本贴给出的重点进行复习。但是，由于作者本人水平有限，可能有很多考点没有规纳出来，也可能有些考点规纳有误，在此，作者本人诚恳希望诸位朋友直面提出，我会不断完善和发布新的关于数据结构复习的总结以及笔记，请大家继续支持作者以及kaoyan.com计算机版。<BR></P>
<P><STRONG>数据结构试题分析和解决方法</STRONG></P>
<P>数据结构是计算机专业的核心课程之一，它主要研究的是数据的各种组织形式及建立在<BR>这些结构之上的各种操作的实现。在计算机专业课的学习中，数据结构课程的作用如灵<BR>魂似的，它不仅为用程序设计语言进行程序设计提供了方法性的理论指导，还在一个更<BR>高的层次上总结了程序设计的常见方法和常用技巧，可以说是程序设计人员的必修课程<BR>。<BR>由于数据结构在教学和实际应用中的重要作用，绝大多数院校的研究生入学考试的专业<BR>课考核中，都把数据结构列为必考科目，其考题难度因为院校的不同而千差万别，但一<BR>般高于该院校本科生的期末考试难度。<BR>1．数据结构课程及考题特点<BR>首先，让我们总结一下数据结构课程及考题的特点，数据结构具有以下特点：<BR>=概念多，对比性强，易记忆<BR>从最简单的线性表到最复杂的图，都有以下内容：类型定义、结构特点。在这些数据结<BR>构的操作中又都有：建立、撤消、插入、删除、查找等基本操作，学习各章时的对比性<BR>很强，使读者很容易建立整体概念。<BR>数据结构中概念较多的章节是树、图、查找、排序等章节。这些章节中需要识记的概念<BR>请读者最好作好笔记，以备复习中随时查阅之用。<BR>=算法灵活，个性突出，不易把握<BR>虽然各种数据结构的基本算法都有相同的操作，但是因为其建立在不同的存储结构上，<BR>所以实现的方法也就截然不同。举个简单的例子：<BR>对于删除结点的操作，在线性表中，由于其结点关系是“前后”关系这种单一的关系，<BR>所以删除时只需要考虑最多另外“两个”（前驱与后继）结点的位置；但是，在图这种<BR>数据结构中，由于其结点关系是“多对多”的复杂关系，所以删除结点时就需要考虑所<BR>有与此结点相关结点信息的修改。<BR>=抽象性强，过于形式化，难于联系实际<BR>数据结构中的研究对象――数据元素，都是从现实生活中抽象出来的，在被组织成不同<BR>形式时，都只是对单纯的数据进行操作，而忽略了其本身所代表的实际意义，比较抽象<BR>。如果读者能适时地很好地联系实际来思考这些问题，就能较好的把握。<BR>=历年考题多有雷同，重复率高<BR>对于同一所学校，在不同的年份中可能出现相同或相似的考题；对于不同的学校，也经<BR>常考一些在算法上极其相似或相同的题。关于这一点，在本书收录的考研真 题中，大家<BR>会很深刻的感受到。<BR>2．数据结构考试题型总结<BR>下面让我们来分析一下数据结构考试题型，由于数据结构的学科特点，概括起来，在考<BR>试中可能出现的考题包括两个方面：<BR>=概念知识<BR>其中概念知识类题的出题内容大概为以下几个方面：<BR>各种结构的定义、特点、适用场合，多种数据结构之间的比较，多种算法性能的比较。<BR>在这些内容的基础上，大体可以有以下几种命题方式：填空、选择、判断等小分值的题<BR>目，这些多是基础题。<BR>=算法分析与设计<BR>算法设计与分析类题的出题内容包括以下几个方面：<BR>算法设计，算法功能分析，算法功能完善。基于以上内容可以出问答、设计等较大分值<BR>的题。在这些题中，难度太高的很少，一般有1至2题是最难的，其他题目较易掌握。<BR>从以上分析来看，基础题加上较简单的设计题，其总分值累计约为70到80分左右，也就<BR>是说，70%到80%的题是基础题。所以，只要我们努力打好基础，把基本题的分拿到手，<BR>不愁数据结构不能顺利过关。<BR>3．解题方法分析<BR>在进行了数据结构的题型分析之后，我们来探讨一下各种类型题的解题方法<BR>=基础题<BR>由于此类基础题涉及范围广，含盖信息量大，考生不可能或很难在较短时间内掌握所有<BR>概念。所以，请大家在平时的复习中，要认真做好读书笔记，及时归纳总结基本概念。<BR>同时，由于此类题难度不大，但是要求考生必须细致入微，否则极易出错，丧失不该掉<BR>的分值。<BR>例1、（同济大学1999年试题）<BR>&nbsp;&nbsp;&nbsp; 阅读下面的程序并写出程序执行结果：<BR>&nbsp;&nbsp;&nbsp; main()<BR>&nbsp;&nbsp;&nbsp; {int x,y,z,w;<BR>&nbsp;&nbsp;&nbsp;&nbsp; z=(x=&amp;#8722;1)?(y=&amp;#8722;1, y+=x+5):(x=7,y=3);<BR>&nbsp;&nbsp;&nbsp;&nbsp; w=y*‘a’/4;<BR>&nbsp;&nbsp;&nbsp;&nbsp; printf(“%d %d %d %c\n”,x,y,z,w);<BR>&nbsp;&nbsp;&nbsp; }<BR>本题的难度并不大，仅需知道C语言的基本知识就可以做对。但是大家做的时候，很多同<BR>学会得出“－1　3　3　72”，而实际上正确答案为：“－1　3　3　H”，因为大家没有<BR>注意到w的输出格式是：“%c”。在第一遍审题的时候，可能比较容易看出这里w的输出<BR>格式是“%c”，但是在解答过程中，经过若干计算之后，得出了结果为72，心理上很容<BR>易发生变化，产生“好啦！终于算出来了”的一瞬间的想法，而受到前三个都是整数的<BR>思维惯性影响，忽视了第四个变量要转换成字符来输出。这就是这个题目的陷阱，大家<BR>一定要重视！<BR>此外，在考试过程中，得许多解题技巧，各个学科，各种考试，都是相通的，考研究生<BR>的同学都是久经沙场的老将了，对于这些技巧应该是不陌生的，比如需选择题的代入法<BR>、排除法等等。比如下面这个选择题，在你无法判断或需很长时间才能判断正确结果的<BR>情况下，一种行之有效的方法就是把备选答案代入到题目中，以验证答案的正确性。<BR>例2、中国科学院计算技术研究所1996年试题<BR>&nbsp;&nbsp;&nbsp; 字符串S满足下式，其中Head和Tail的定义同广义表类似，如Head(‘xyz’)=‘x’<BR>，Tail(‘xyz’)=‘yz’，则S=_____。<BR>&nbsp;&nbsp;&nbsp; Concat(Head(Tail(S))，Head(Tail(Tail(S))))=‘dc’<BR>（A）abcd&nbsp;&nbsp;&nbsp; （B）acbd&nbsp;&nbsp; （C）acdb&nbsp;&nbsp; （D）adcb<BR>选择题可用代入法求解，把答案一个个代入即可验证，本题答案为D。<BR>=算法分析类题<BR>算法分析的有效工具是：D-F图，PDL语言，程序流图。由于目前的程序设计中，最终都<BR>要使用面向过程的结构化程序设计方法，程序或算法内部具有很强的模块化特性，所以<BR>分析时可以按照模块分解的方法，把具有独立功能的相关语句看作一个整体，完成某种<BR>功能。这样就会站在算法的全局来看待问题，从而拓宽了思路。总体来说，一个完整的<BR>算法大致分成三个模块：一是输入数据模块，二是算法处理模块，三是输出结果模块。<BR>通常情况下，算法处理模块中的语句是核心，难度也最大；而输入模块与输出模块难度<BR>较小，读者可以先攻克这两个模块。<BR>由于算法分析类题目是遵循别人的思路进行解题，所以难度较大，需要一定的算法经验<BR>积累。这种积累需要靠大量的练习而来。<BR>比如：“两个数的交换操作”，就有以下两种不同的实现方法：<BR>① temp=a;a=b;b=temp;<BR>② x=x+y;y=x-y;x=x-y;<BR>在第一种解法中，其思路是最普遍的思路，也是较易理解的，但思路二则是一种不常见<BR>的思路，加大了算法的复杂性。在考试中，有的考题为了加大题目本身难度就可能使用<BR>第二种方法（但读者在自己设计算法时则应该尽量避免使用非常见的算法）。所以，平<BR>时练习时，应积极寻求一题多解，探寻多种思路，并将好的方法记录下来。但是，请读<BR>者放心，并不是所有的考题都如此怪异，其算法多数是常见的。<BR>此外，在算法分析题中，读者应十分注意一些细节信息，例如算法的注释、算法核心变<BR>量的名称，往往这都是一些提示性的信息。从这些提示信息中，读者可以推算此变量的<BR>含义及作用，由此推出其所在模块的功能，再将该模块放在整个算法中来理解，那么整<BR>个算法的分析工作也就完成了。<BR>=算法设计题<BR>算法设计类题目是数据结构分值最大的题，往往也是决定考生能否得高分的关键。<BR>算法就是解决问题的方法。计算机算法具有以下特性：有穷性，确定性，可执行性，0个<BR>或多个输入，1个或多个输出。算法的主要类型分为两类：数值算法与非数值算法。<BR>算法设计的常用工具有：与算法分析题一样，算法设计工具有N－F，流程图，PDL语言。<BR><BR>算法设计的常用方法主要有两种：<BR>第一种，模块化结构化设计方法，即把问题分成几个独立的子模块，然后把各子模块组<BR>合起来完成算法的功能<BR>第二种，自顶向下、逐步求精的结构化设计方法，即从上到下一层逐步细化求解过程，<BR>直到写出最终的算法来。<BR>从对算法设计的要求来说，下面是4条重要的准则:<BR>（1）要确保算法的正确性；<BR>（2）要使算法具有良好的可读性；<BR>（3）要使算法具有良好的健壮性；<BR>（4）要使算法占用较少的时空资源。<BR>在以上四点中，前两者是极其重要的，往往是算法设计题取得高分的关键。正确性自不<BR>必多说，关于算法的可读性，一是必须写上算法注释，二是最好在写算法前加上算法的<BR>说明，这个说明包括算法功能，算法核心变量的含义，模块的含义及其参数的作用。<BR>　　值得注意的是，有些学校的考题为了增加难度，就要求考生写出时间复杂度最小的<BR>，或者是限制了额外的变量的使用。这样就要求我们在平时的复习当中，在第四个要求<BR>上多下功夫，不仅要写出正确的算法，而且要写出最优的算法来。<BR>最后，从考试的角度来说，读者在平时的练习中就应该有意加强“规范”的意识和练习<BR>，否则难以保证在考试中能写出既清晰又不多余的算法注释和算法说明来。从阅卷者批<BR>改试卷的角度考虑，也应该这样做，因为如果阅卷者看到一份结构清晰、注释明了的答<BR>卷，必有赏心悦目的感觉，这样即使有些许错误，下手必然也会慎重；反之，如果算法<BR>冗长而没有注释，Begin end等嵌套匹配混乱，即使解答是正确的，阅卷者看了也必定头<BR>疼！这里还须提醒考生一点的是，不要追求算法的新奇，最好按照普通的思维方式，通<BR>常的解法来做，因为万一你的算法独出心裁，虽然是个好算法，而阅卷者不能再一两分<BR>钟内理解，可能会因此而损失惨重，尽管通常来说阅卷者都会认真对待每一份考卷，但<BR>是大家还是不要冒险。<BR>4．复习方法指导<BR>下面简单说一下数据结构的学习方法和读者可能会遇到的误区。<BR>我们认为学习数据结构这门课程至少要经历三个过程，方可真正的掌握这门课程，得到<BR>一个满意的成绩。这个过程简单来说就是三个字：活→死→活。<BR>首先，是一个学“活”的过程，就要要求我们对书中的每一个算法，能够在脑海中建立<BR>起相应的模型，而不是死板的算法。比如树的遍历非递归算法，在入栈与出栈的过程中<BR>，我们就要在脑海中形成访问树每个结点的过程，真正掌握住这个算法。这样，全书复<BR>习下来，你的脑海中就有了整个数据结构的模型概念，对任何一个陌生的算法，将不感<BR>到生疏和害怕。<BR>有些同学到了此处就觉得数据结构已经学好，可以万事大吉了，其实这还远远不够，如<BR>果参加考试，往往会拿不到高分，甚至还会纳闷，为何自己数据结构学的这样好，成绩<BR>却不尽如人意，因此产生了批卷老师判错的想法。所以第二个过程，就是一个学“死”<BR>的过程，这个过程要求，要记住书中的算法（功利一点就是要背诵会所报考学校的考试<BR>要求的算法）。有的学校有别的特殊要求，也一并背会。如上海交通大学喜欢考平均复<BR>杂度的分析这样的题目，我们在书上可以找到这样的分析一共十一个，全部背会，就免<BR>去了在考场上分析的麻烦，如果连答案都能记住，那么，也不会因为粗心失分了。这一<BR>过程也许有些枯燥，但却是最重要的过程，比如说背会了树的后序遍历非递归，遇到了<BR>像求某个结点的所有祖先，两个结点的共同祖先这样的题，不用想，直接套用。这样才<BR>是考试的高分的关键：在考场上，遇到考题，不用思考，直接从脑海中找匹配的算法，<BR>直接引用。<BR>有了第二个过程的辛苦，我们就可以得到一个比较高的分数了，如果还想提高，就要进<BR>行第三个过程，再学“活”的过程。这一个过程中就要要求我们，在第二步的基础上，<BR>多进行思考，看看有哪些算法有共性，比如说：树的前序非递归遍历算法和图的深度优<BR>先遍历算法是不是类似啊，有些什么不同，有些什么相同，为什么会相同；森林转化为<BR>二叉树和图的生成树的算法也是这样，等等。总结出这种共性，这样就能正确有效的记<BR>忆算法，同时，遇到难题不至于慌乱，能够从容下手解题。<BR>对于总结共性问题上，这里举一小个例子，比如树的遍历，不管是递归还是非递归，也<BR>不管是线索树，还是头结点有父母信息的树，它的遍历其实就是一个寻找到遍历的第一<BR>个结点，然后再寻找它的后继结点的过程，我们归纳到此处，就可以试着总结一下三种<BR>遍历的后继结点是哪个，有几种情况：<BR>对于前序遍历，它的后继如下：<BR>（１）若有左孩子，则后继是左孩子；<BR>（２）若无左孩子，有右孩子，则后继是右孩子；<BR>（３）若既无左孩子，又无右孩子，则是一片叶子；再讨论：<BR>（ａ）若是其父母的左孩子，且父母有右孩子，则后继是父母的右孩子。<BR>（ｂ）若是其父母的左孩子，且父母无右孩子；<BR>　　（ｃ）若是其父母的右孩子。<BR>ｂ，ｃ都表示这是某个节点的左子树前序遍历的最后一个节点，则需要找第一个有右子<BR>树的“左祖先”（定义“左祖先”，即找第一个使得当前节点在这个祖先的左子树上）<BR>，然后后继就是这个祖先的右孩子。<BR>对于中序遍历，它的后继如下：<BR>（１）如有右孩子，后继是右孩子的最左下节点；<BR>（２）若无右孩子，且是父母的左孩子，则后继就是父母；<BR>（３）若无右孩子，且是父母的右孩子，则一直上溯到第一个“左祖先”（定义如前）<BR>则后继就是这个祖先。若无这样的祖先，说明已经遍历完毕。<BR>对于后序遍历，它的后继如下：<BR>（１）若是父母的右孩子，则后继是父母；<BR>（２）若是父母的左孩子，且父母无右子树，则后继是父母；<BR>（３）若是父母的左孩子，父母有右子树，则后继是父母右子树的最先访问到的节点（<BR>指向父母的右子树后，一直往左，若不行的话，往右一步，一直到叶子）<BR>总结完了，想一想，我们还能得到哪些提示？经常有一类型题目，要求求某个结点的直<BR>接前驱。其实求前序遍历的前驱和求后序遍历的后继是一样的，只不过把左换成右而已<BR>，前序遍历的求后继和后序遍历的求前驱、中序遍历的求前驱和中序遍历求后继都有这<BR>样的对称关系。因此，总结出共性的东西，许多题目就可以迎刃而解了。问一问读到这<BR>里的读者，你现在能够自己在脑子里面，非常轻松地像上面那样，把这个例子里面的情<BR>况都条理清楚地分析总结出来吗？如果现在还不行，到考试之前，你必须掌握到这种程<BR>度，才能得到一个自己很满意的分数。<BR>经过以上的三个过程复习，相信读者对数据结构的掌握就可以到达比较高的水平了，如<BR>果参加研究生的如许考试，获得一个比较满意的成绩也很有希望了。当然，达到这一步<BR>并不容易，大量的练习是真正掌握的必由之路。因此，我们建议大家能够下功夫把本书<BR>中的题目完整地做一遍。能够真正把本书中的所有题都掌握，绝不仅仅意味着仅会了书<BR>中这几百道题目，而是意味着对数据结构这门课程的理解，以及对问题的分析能力都有<BR>很大的提高，这样在考场上即使遇到未曾见过的题目，也就可以从容应对了！<BR></P><img src ="http://www.blogjava.net/songfei/aggbug/20262.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/songfei/" target="_blank">天外飞仙</a> 2005-11-17 16:32 <a href="http://www.blogjava.net/songfei/articles/20262.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>