zoukankan      html  css  js  c++  java
  • [Algorithm]线性表

    一. 线性表基础算法


    1.线性表插入操作

     1 // 线性表插入操作(在第i(1≤i≤L.length+1)个位置上插入新元素elem)
     2 bool InsertSeq( SeqList& L, int i, ElemType elem )
     3 {
     4     if ( i < 1 || i>L.length + 1 || L.length >= MAXSIZE )
     5         return false;
     6     for ( j = L.length - 1; j >= i - 1; j-- )
     7         L.elem[j + 1] = L.elem[j];
     8     L.elem[j + 1] = elem;
     9     L.length++;
    10     return true;
    11 }

    说明:

    • 插入操作: 可选位置为1≤i≤L.length+1
    • 最好情况: 表尾(i=n+1)插入, O(1)
    • 最坏情况: 表头(i=1)插入, O(n)
    • 平均情况: 设 $Pi=frac {1}{(n+1)}$ 是在第i个位置插入一个结点的概率,则在长度为n的线性表中插入一个结点所需的移动结点的平均次数为$frac{n}{2}$次,即O(n): $$sum_{i=1}^{n+1} Picdot{(n+1-i)}=frac{1}{n+1}cdotsum_{i=1}^{n+1} {(n-i+1)}=frac{1}{n+1}cdotfrac{n(n+1)}{2}=frac{n}{2}$$

    2.线性表删除操作

    1 bool DeleteSeq( SeqList& L, int i, ElemType& elem )
    2 {
    3     for ( i<1 || i>L.length ) return false;
    4     elem = L.elem[i - 1];
    5     for ( j = i; j < L.length; j++ )
    6         L.elem[j - 1] = L.elem[j];
    7     L.length--;
    8     return true;
    9 }
    • 最好情况: 删除表位(i=n),O(1)
    • 最坏情况: 删除表头(i=1),O(n)
    • 平均情况: 设$Pi=frac{1}{n}$是删除第i个位置上结点的概率,则在长度为n的线性表中删除一个结点所需移动结点的平均次数为$frac{n-1}{2}$次,即O(n):$$sum_{i=1}^{n}Picdot{(n-i)}=frac{1}{n}sum_{i=1}^{n}{(n-i)}=frac{1}{n}cdotfrac{n(n-1)}{2}=frac{n-1}{2}$$

    3.线性表查找操作

    1 int LocateSeq( SeqList& L, ElemType elem )
    2 {
    3     for ( i = 0; i < L.length; i++ )
    4         if ( L.elem[i].key == elem.key )
    5             return i + 1;
    6     return 0;
    7 }
    • 最好情况: 查找到表头,O(1)
    • 最坏情况: 查找到表尾,O(n)
    • 平均情况: 设$Pi=frac{1}{n}$是查找元素在第i(1≤i≤L.length)个位置上的概率,则在长度为n的线性表中查找值为elem的元素所需比较的平均次数为$frac{n+1}{2}$次,O(n):$$sum_{i=1}^{n}Picdot{i}=frac{1}{n}cdotsum_{i=1}^{n}{i}=frac{1}{n}cdotfrac{n(n+1)}{2}=frac{n+1}{2}$$

    二.线性表综合应用


    1.删除线性表中所有值为x的数据元素

    1 bool DeleteX( SeqList& L, ElemType x )
    2 {
    3     int k = 1;
    4     for ( i = 1; i <= L.length; i++ )
    5         if ( L.elem[i].key != x.key )
    6             L.elem[k++] = L.elem[i];
    7     L.length = k;
    8     return true;
    9 }

    2.从有序顺序表中删除值在[s,t]的所有元素

    1 bool DeleteS2TOrderedSeq( SeqList& L, int s, int t )
    2 {
    3     for ( i = 1; i <= L.length&&L.elem[i].key < s; i++ );    // 找≥s的第一个元素
    4     for ( j = i; j <= L.length&&L.elem[j].key <= t; j++ );    // 找>t的第一个元素
    5     while ( j <= L.length )
    6         L.elem[i++] = L.elem[j++];
    7     L.length = i;
    8     return true;
    9 }

    3.从顺序表中删除值在[s,t]的所有元素

    1 bool DeleteS2TSeq( SeqList& L, int s, int t )
    2 {
    3     int k = 1;
    4     for ( i = 1; i <= L.length; i++ )
    5         if ( L.elem[i].key<s || L.elem[i].key>t )
    6             L.elem[k++] = L.elem[i];
    7     L.length = k;
    8     return true;
    9 }

    4.从有序顺序表中删除所有值重复的元素

    1 bool DeleteSameOrderedSeq( SeqList& L )
    2 {
    3     int k = 1;
    4     for ( i = 2; i <= L.length; i++ )
    5         if ( L.elem[i].key != L.elem[k].key )
    6             L.elem[++k] = L.elem[i];
    7     L.length = k;
    8     return true;
    9 }

    5.将两个有序顺序表合并为一个新的有序顺序表

     1 bool Merge( SeqList A, SeqList B, SeqList& C )
     2 {
     3     int i = 1, j = 1, k = 1;
     4     while ( i<=A.length&&j<=B.length )
     5     {
     6         if ( A.elem[i].key <= B.elem[j].key )
     7             C.elem[k++] = A.elem[i++];
     8         else
     9             C.elem[k++] = B.elem[j++];
    10     }
    11     while ( i <= A.length ) C.elem[k++] = A.elem[i++];
    12     while ( j <= B.length ) C.elem[k++] = B.elem[j++];
    13     C.length = k - 1;
    14     return true;
    15 }

    6.原数组A[m+n]={a1,a2,...,am,b1,b2,...,bn},现要求转变为A[m+n]={b1,b2,...,bn,a1,a2,...,am}

     1 // 元素倒置
     2 void Reverse( ElemType A[], int s, int e )
     3 {
     4     for ( i = s; i < ( s + e ) / 2; i++ )
     5         swap( A[i], A[s + e - i - 1] );
     6 }
     7 
     8 void ExChange( ElemType A[], int m, int n )
     9 {
    10     Reverse( A, 0, m );
    11     Reverse( A, m, m + n );
    12     Reverse( A, 0, m + n );
    13 } 

    7.线性表(a1,a2,...,an)递增有序,设计算法花最少时间找到数值为x的元素:

    1)找到,则与其后继元素位置互换

    2)未找到,将其插入表中并使表中元素仍然递增有序

     1 // 使用折半查找的方法
     2 void SearchExchangeInsert( ElemType A[], int n, ElemType x )
     3 {
     4     int low = 1, high = n;
     5     while ( low <= high )
     6     {
     7         mid = ( low + high ) / 2;
     8         if ( x.key == A[mid].key )
     9         {
    10             if ( mid != n )
    11                 swap( A[mid], A[mid + 1] );
    12             return;
    13         }
    14         else if ( x.key < A[mid].key ) high = mid - 1;
    15         else low = mid + 1;
    16     }
    17     for ( j = n; j >= high + 1; j-- )
    18         A[j + 1] = A[j];
    19     A[j + 1] = x;
    20 }

    8.设计算法将一维数组R中的序列循环左移p(0<p<n)个位置(算法思想和⑥相同)

     1 // 元素倒置
     2 void Reverse( ElemType A[], int s, int e )
     3 {
     4     for ( i = s; i < ( s + e ) / 2; i++ )
     5         swap( A[i], A[s + e - i - 1] );
     6 }
     7 
     8 void ShiftLeft( ElemType R[], int n, int p )
     9 {
    10     Reverse( R, 0, p );
    11     Reverse( R, p, n );
    12     Reverse( R, 0, n );
    13 }

    9.长度为L(L≥1)的升序序列S,处在$lceilfrac{L}{2} ceil$个位置的数成为S的中位数,设计一个在时空都尽量高效的算法找出两个等长序列A和B的中位数

     1 int FindMidFromABOrderedSeq( int A[], int B[], int n )
     2 {
     3     int s1, s2, e1, e2, m1, m2;
     4     s1 = s2 = 0;
     5     e1 = e2 = n - 1;
     6     while ( s1 != e1 || s2 != e2 )
     7     {
     8         m1 = ( s1 + e1 ) / 2;
     9         m2 = ( s2 + e2 ) / 2;
    10         if ( A[m1] == B[m2] )
    11             return A[m1];
    12         else if ( A[m1] < B[m2] )
    13         {
    14             if ( !( ( s1 + e1 ) % 2 ) )
    15                 s1 = m1, e2 = m2;
    16             else
    17                 s1 = m1 + 1, e2 = m2;
    18         }
    19         else
    20         {
    21             if ( !( ( s2 + e2 ) % 2 ) )
    22                 s2 = m2, e1 = m1;
    23             else
    24                 s2 = m2 + 1, e1 = m1;
    25         }
    26     }
    27     return A[s1] < B[s2] ? A[s1] : B[s2];
    28 }

    三.线性表的链式表示


    1.采用头插法建立单链表

     1 LinkList CreateList( LinkList& L )
     2 {
     3     L = ( LinkList ) malloc( sizeof( LNode ) );
     4     L->next = NULL;
     5     scanf( "%d", &x );
     6     while ( x != 9999 )
     7     {
     8         s = ( LNode* ) malloc( sizeof( LNode ) );
     9         s->data = x;
    10         s->next = L->next;
    11         L->next = s;
    12         scanf( "%d", &x );
    13     }
    14     return L;
    15 }

    2.采用尾插法建立单链表

     1 LinkList CreateList( LinkList& L )
     2 {
     3     L = ( LinkList ) malloc( sizeof( LNode ) );
     4     L->next = NULL;
     5     r = L;
     6     scanf( "%d", &x );
     7     while ( x != 9999 )
     8     {
     9         s = ( LNode* ) malloc( sizeof( LNode ) );
    10         s->data = x;
    11         r->next=s;
    12         r = s;
    13         scanf( "%d", &x );
    14     }
    15     r->next = NULL;
    16     return L;
    17 }

    四.线性表相关综合算法


    1.递归删除不带头结点的单列表L中所有值为x的结点

    1 void DeleteX( LinkList& L, ElemType x )
     2 {
     3     if ( !L ) return;
     4     if ( L->data == x )
     5     {
     6         q = L;
     7         L = L->next;
     8         free( q );
     9         DeleteX( L, x );
    10     }
    11     else
    12         DeleteX( L->next, x );
    13 } 

    2.删除带头结点的单链表L中所有值为x的结点

     1 void DeleteX( LinkList& L, ElemType x )
     2 {
     3     pre = L;
     4     p = L->next;
     5     while ( p )
     6     {
     7         if ( p->data == x )
     8         {
     9             q = p;
    10             pre->next = p->next;
    11             p = p->next;
    12             free( q );
    13         }
    14         else
    15         {
    16             pre = p; p = p->next;
    17         }
    18     }
    19 }

    3.反向输出带头结点的单链表L的每个结点的值

    1 void PrintX( LinkList L )
    2 {
    3     if ( !L )return;
    4     PrintX( L->next );
    5     visit( L );
    6 }

    4.删除带头结点单链表L中最小值结点

     1 LinkList DeleteMin( LinkList& L )
     2 {
     3     LinkList p, s, pre, q;
     4     p = s = L->next;
     5     pre = q = L;
     6     while ( p )
     7     {
     8         if(p->data<s->data )
     9         {
    10             s = p; q = pre;
    11         }
    12         pre = p;
    13         p = p->next;
    14     }
    15     q->next = s->next;
    16     free( s );
    17     return L;
    18 }

    5.将带头结点的单链表就地逆置,"就地"指辅助空间复杂度为O(1)

     1 LinkList Reverse( LinkList L )
     2 {
     3     LinkList p, q;
     4     p = L->next;
     5     L->next = NULL;
     6     while ( p )
     7     {
     8         q = p->next;
     9         p->next = L->next;
    10         L->next = p;
    11         p = q;
    12     }
    13     return L;
    14 }

    6.将带头结点的单链表L排序,使其递增有序

     1 void InsertSort( LinkList& L )
     2 {
     3     LinkList p, pre, r;
     4     p = L->next; r = p->next;
     5     p->next = NULL; p = r;
     6     while ( p )
     7     {
     8         r = p->next;
     9         pre = L;
    10         while ( pre->next&&pre->next->data < p->data )
    11             pre = pre->next;
    12         p->next = pre->next;
    13         pre->next = p;
    14         p = r;
    15     }
    16 }

    7.在带头结点的单链表中,删除值介于(s,t)之间的元素

     1 void DeleteS2T( LinkList& L, int s, int t )
     2 {
     3     LinkList pre, p;
     4     pre = L; p = pre->next;
     5     while ( p )
     6     {
     7         if ( p->data > s && p->data < t )
     8         {
     9             pre->next = p->next;
    10             free( p );
    11             p = pre->next;
    12         }
    13         else
    14         {
    15             pre = p;
    16             p = p->next;
    17         }
    18     }
    19 }

    8.找出两个单链表的公共结点

     1 LinkList SearchCommon( LinkList L1, LinkList L2 )
     2 {
     3     LinkList pA, pB;
     4     int lenA, lenB, dist;
     5     pA = L1->next, pB = L2->next;
     6     lenA = lenB = 0;
     7     while ( pA ) { pA = pA->next; lenA++; }
     8     while ( pB ) { pB = pB->next; lenB++; }
     9     pA = L1->next, pB = L2->next;
    10     if ( lenA > lenB )
    11     {
    12         dist = lenA - lenB;
    13         while ( dist-- ) pA = pA->next;
    14     }
    15     else
    16     {
    17         dist = lenB - lenA;
    18         while ( dist-- ) pB = pB->next;
    19     }
    20     while ( pA )
    21     {
    22         if ( pA == pB ) return pA;
    23         pA = pA->next, pB = pB->next;
    24     }
    25     return NULL;
    26 }

     9.带表头结点的单链表,按递增次序输出单链表中各结点的数据元素,并释放空间

     1 void AscDelete( LinkList& L )
     2 {
     3     LinkList p, s, pre, r;
     4     while ( L->next )
     5     {
     6         s = p = L->next; r = pre = L;
     7         while ( p )
     8         {
     9             if ( p->data < s->data )
    10             {
    11                 s = p; r = pre;
    12             }
    13             pre = p;
    14             p = p->next;
    15         }
    16         r->next = s->next;
    17         visit( s );
    18         free( s );
    19     }
    20     free( L );
    21 }

     10.将带头结点的单链表A分解成两个带头结点的单链表A和B,A中含有奇数序号元素,B中含有偶数序号元素且相对位置不变

     1 // 法一
     2 LinkList Split( LinkList& A )
     3 {
     4     LinkList p, B, rA, rB;
     5     int i = 0;
     6     p = A->next;
     7     B = ( LinkList ) malloc( sizeof( LNode ) );
     8     rA = A; A->next = NULL;
     9     rB = B; B->next = NULL;
    10     while ( p )
    11     {
    12         i++;
    13         if (i%2)
    14         {
    15             rA->next = p; rA = p;
    16         }
    17         else
    18         {
    19             rB->next = p; rB = p;
    20         }
    21         p = p->next;
    22     }
    23     rA->next = NULL;
    24     rB->next = NULL;
    25     return B;
    26 }
    27 
    28 // 法二
    29 LinkList Split( LinkList& A )
    30 {
    31     LinkList p, B, rB, pre;
    32     int i = 0;
    33     B = ( LinkList ) malloc( sizeof( LNode ) );
    34     rB = B;
    35     pre = A; p = pre->next;
    36     while ( p )
    37     {
    38         i++;
    39         if ( i % 2 == 0 )
    40         {
    41             pre->next = p->next;
    42             rB->next = p;
    43             rB = p;
    44             p = pre->next;
    45         }
    46         else
    47         {
    48             pre = p;
    49             p = p->next;
    50         }
    51     }
    52     return B;
    53 }

    11.C={a1,b1,a2,b2,...,an,bn}为线性表,带有头结点,设计一个就地算法将其拆分为两个线性表,使A={a1,a2,...,an},B={bn,...,b2,b1}

     1 LinkList Split( LinkList& A )
     2 {
     3     LinkList B, pre, p;
     4     int i = 0;
     5     B = ( LinkList ) malloc( sizeof( LNode ) );
     6     pre = A; p = pre->next;
     7     while ( p )
     8     {
     9         i++;
    10         if ( i % 2 == 0 )
    11         {
    12             pre->next = p->next;
    13             p->next = B->next;
    14             B->next = p;
    15             p = pre->next;
    16         }
    17         else
    18         {
    19             pre = p;
    20             p = p->next;
    21         }
    22     }
    23     return B;
    24 }

    12.在递增有序的带头结点的单链表中,数值相同的只保留一个,使表中不再有重复的元素

     1 void DeleteSame( LinkList& L )
     2 {
     3     LinkList p, q;
     4     p = L->next;
     5     while ( p )
     6     {
     7         q = p->next;
     8         if ( q&&q->data == p->data )
     9         {
    10             p->next = q->next;
    11             free( q );
    12         }
    13         else
    14             p = p->next;
    15     }
    16 }

    13.将两个按元素值递增的单链表合并为一个按元素值递减的单链表

     1 void MergeList( LinkList& LA, LinkList& LB )
     2 {
     3     LinkList pA, pB, q;
     4     pA = LA->next; pB = LB->next;
     5     LA->next = NULL;
     6     while ( pA&&pB )
     7     {
     8         if ( pA->data <= pB->data )
     9         {
    10             q = pA->next;
    11             pA->next = LA->next;
    12             LA->next = pA;
    13             pA = q;
    14         }
    15         else
    16         {
    17             q = pB->next;
    18             pB->next = LA->next;
    19             LA->next = pB;
    20             pB = q;
    21         }
    22     }
    23     if ( pA )
    24         pB = pA;
    25     while(pB )
    26     {
    27         q = pB->next;
    28         pB->next = LA->next;
    29         LA->next = pB;
    30         pB = q;
    31     }
    32     free( LB );
    33 }

    14.A,B为两个元素递增有序的单链表(带头结点),设计算法从A,B中公共元素产生单链表C,要求

     1 void MergeList( LinkList& LA, LinkList& LB )
     2 {
     3     LinkList pA, pB, q;
     4     pA = LA->next; pB = LB->next;
     5     LA->next = NULL;
     6     while ( pA&&pB )
     7     {
     8         if ( pA->data <= pB->data )
     9         {
    10             q = pA->next;
    11             pA->next = LA->next;
    12             LA->next = pA;
    13             pA = q;
    14         }
    15         else
    16         {
    17             q = pB->next;
    18             pB->next = LA->next;
    19             LA->next = pB;
    20             pB = q;
    21         }
    22     }
    23     if ( pA )
    24         pB = pA;
    25     while ( pB )
    26     {
    27         q = pB->next;
    28         pB->next = LA->next;
    29         LA->next = pB;
    30         pB = q;
    31     }
    32     free( LB );
    33 }

    15.求两个元素递增排列的链表(带头结点)A和B的交集并存放于A链表中,并释放其他结点

     1 void Intersect( LinkList& LA, LinkList& LB )
     2 {
     3     LinkList pA, pB, r, q;
     4     pA = LA->next; pB = LB->next;
     5     r = LA; LA->next = NULL;
     6     while ( pA&&pB )
     7     {
     8         if ( pA->data == pB->data )
     9         {
    10             r->next = pA;
    11             r = pA;
    12             pA = pA->next;
    13             q = pB;
    14             pB = pB->next;
    15             free( q );
    16         }
    17         else if ( pA->data < pB->data )
    18         {
    19             q = pA;
    20             pA = pA->next;
    21             free( q );
    22         }
    23         else
    24         {
    25             q = pB;
    26             pB = pB->next;
    27             free( q );
    28         }
    29     }
    30     r->next = NULL;
    31     while ( pA )
    32     {
    33         q = pA;
    34         pA = pA->next;
    35         free( q );
    36     }
    37     while ( pB )
    38     {
    39         q = pB;
    40         pB = pB->next;
    41         free( q );
    42     }
    43     free( LB );
    44 }

    16.判断单链表序列B是否是A的连续子序列(不带头结点)

     1 bool IsSubsequence( LinkList A, LinkList B )
     2 {
     3     LinkList pA, pB, h;
     4     pA = A; pB = B;
     5     h = pA;
     6     while ( pA&&pB )
     7     {
     8         if ( pA->data == pB->data )
     9         {
    10             pA = pA->next;
    11             pB = pB->next;
    12         }
    13         else
    14         {
    15             h = h->next;
    16             pA = h;
    17             pB = B;
    18         }
    19     }
    20     if ( pB ) return false;
    21     return true;
    22 }

    17.判断带头结点的循环双链表是否对称

     1 bool IsSymmetry( DLinkList L )
     2 {
     3     DLinkList p, q;
     4     p = L->next; q = L->prior;
     5     while ( p != q && q->next != p )
     6     {
     7         if ( p->data != q->data )
     8             return false;
     9         p = p->next;
    10         q = q->next;
    11     }
    12     return true;
    13 }

    18.将循环单链表h2链接到h1之后

     1 LinkList Link( LinkList& h1, LinkList& h2 )
     2 {
     3     LinkList p;
     4     p = h1;
     5     while ( p->next != h1 )p = p->next;
     6     p->next = h2;
     7     p = h2;
     8     while ( p->next != h2 )p = p->next;
     9     p->next = h1;
    10     return h1;
    11 }

    19.带头结点的循环链表,按递增次序输出循环链表中各结点的数据元素,并释放空间

     1 void AscDelete( LinkList& L )
     2 {
     3     LinkList p, s, r, pre;
     4     while ( L->next != L )
     5     {
     6         s = p = L->next; r = pre = L;
     7         while ( p != L )
     8         {
     9             if ( p->data < s->data )
    10             {
    11                 s = p; r = pre;
    12             }
    13             pre = p;
    14             p = p->next;
    15         }
    16         visit( s );
    17         r->next = s->next;
    18         free( s );
    19     }
    20     free( L );
    21 }

    20.查找单链表(带头结点)中倒数第k个位置的结点,成功:则输出并返回true,否则只返回false

     1 bool SearchBackwardK( LinkList L, int k )
     2 {
     3     LinkList p, q;
     4     int count;
     5     p = q = L->next;
     6     count = 0;
     7     while (p)
     8     {
     9         if ( count < k ) count++;
    10         else q = q->next;
    11         p = p->next;
    12     }
    13     if ( count < k ) return false;
    14     visit( q );
    15     return true;
    16 }

    21.链表中data绝对值相等的点,只保留第一次出现的结点($vert{data}vertle{n}$)

     1 void DeleteSameAbs( LinkList L, int n )
     2 {
     3     LinkList pre, p;
     4     int *B, pos;
     5     B = ( int * ) malloc( sizeof( int )*( n + 1 ) );
     6     for ( int i = 0; i < n + 1; i++ )
     7         B[i] = 0;
     8     pre = L; p = L->next;
     9     while ( p )
    10     {
    11         pos = p->data > 0 ? p->data : -p->data;
    12         if ( B[pos] == 0)
    13         {
    14             B[pos] = 1; pre = p; p = p->next;
    15         }
    16         else
    17         {
    18             pre->next = p->next; free( p ); p = pre->next;
    19         }
    20     }
    21     free( B );
    22 }

    22.带头结点的循环双链表递增排序

     1 void AscSort( DLinkList L )
     2 {
     3     DLinkList p, q, r;
     4     if ( !L ) return;
     5     p = L->next; q = p->next; r = q->next;
     6     while ( q!=L )
     7     {
     8         while ( p != L && p->data > q->data )
     9             p = p->prior;
    10         // 脱链结点p
    11         q->prior->next = r;
    12         r->prior = q->prior;
    13         // 插入节点p
    14         q->next = p->next;
    15         q->prior = p;
    16         p->next->prior = q;
    17         p->next = q;
    18         // 归位(相对位置)
    19         q = r;
    20         p = q->prior;
    21         r = r->next;
    22     }
    23 }
  • 相关阅读:
    JSP中文乱码
    Java Enum 浅析
    详解 Tomcat: The value for the useBean class attribute is invalid
    PHP+ACCESS 实例
    MySQL limit实际用法的详细解析
    JSP获取当前时间
    sql where 1=1和 0=1 的作用
    利用Quartus设计4位同步二进制加法计数器
    JSP各种路径的获取
    JSP连接MYSQL数据库
  • 原文地址:https://www.cnblogs.com/brianyi/p/10173344.html
Copyright © 2011-2022 走看看