資料結構複習:幾種排序演算法的C++實現和二叉樹的相關演算法實現

來源:互聯網
上載者:User

      用c語言實現了二叉樹的資料定義,二叉樹的構建、銷毀,以及先序、中序、後序的遞迴演算法,非遞迴演算法正在研究中。

/*--------------------------------------------------------------------------------------------*/

// 二叉樹的二叉鏈表格儲存體結構C語言實現。                                                   

// 實現了利用先序序列建立一棵二叉樹,先序、中序、後序遍曆演算法的遞迴

// 和非遞迴演算法。                                                                                      

// 版本: v1.0

// 環境:Visual C++ 6.0

// 作者: sunnyrain

// 日期: 2007-8-24

/*--------------------------------------------------------------------------------------------*/

//BiTree.h

struct BiTNode   //採用二叉鏈表格儲存體結構
{
 char data;
 struct BiTNode* lchild;
 struct BiTNode* rchild;
}BiTNode;

struct BiTNode* CreateBiTree(); 
int DestroyBiTree(struct BiTNode* T);
int visit(char elem);

//遞迴遍曆演算法
int PreOrderTraverse_R(struct BiTNode* T, int (*visit)(char elem));
int InOrderTraverse_R(struct BiTNode* T, int (*visit)(char elem));
int PostOrderTraverse_R(struct BiTNode* T, int (*visit)(char elem));

//非遞迴遍曆演算法
void PreOrderTraverse(struct BiTNode* T, int (*visit)(char elem));
void InOrderTraverse(struct BiTNode* T, int (*visit)(char elem));
void PostOrderTraverse(struct BiTNode* T, int (*visit)(char elem));

//stack.h 堆棧資料結構,用於非遞迴演算法中的附加空間

#define STACK_SIZE 256

struct stack
{
 struct BiTNode* elem[STACK_SIZE];
 int top;  //top總是指向棧頂元素的上一個元素
 int bottom; //恒0
};
void initStack(struct stack* s);
struct BiTNode* getTop(struct stack* s);
struct BiTNode* pop(struct stack* s);
void push(struct stack* s,struct BiTNode* p);
int isEmpty(struct stack* s);

//stack.c 堆棧的實現

#include<stdio.h>
#include<string.h>
#include "stack.h"

//初始化堆棧為0,棧指標為0
void initStack(struct stack* s)
{
 memset(s->elem,0,STACK_SIZE);
 s->top = s->bottom = 0;
}

//擷取棧頂元素,棧頂指標不變
struct BiTNode* getTop(struct stack* s)
{
 return s->elem[s->top-1];
}

//彈出&返回棧頂元素
struct BiTNode* pop(struct stack* s)
{
 if(s->top == s->bottom)  //若棧空
 {
  printf("Stack is empty!/n");
  return 0;
 }

 --s->top;
 return s->elem[s->top];
}

//將pB指標壓入棧中
void push(struct stack* s,struct BiTNode* pB)
{
 if(s->top<STACK_SIZE)  //棧未滿
 {
  s->elem[s->top] = pB;
  ++s->top;
 }
 else 
  printf("Stack is full!/n");
}

//判斷棧是否為空白,空返回非0
int isEmpty(struct stack* s)
{
 return s->top == s->bottom;
}
//BiTree.c 二叉樹建立、銷毀、遞迴演算法實現

#include<stdio.h>
#include<malloc.h>
#include "BiTree.h"
#include "stack.h"

struct BiTNode* CreateBiTree() //採用先序遞迴方法建立一棵二叉樹
{
 struct BiTNode* T;
 char ch,tmp;
 printf("please input the value of the node:/n");
 scanf("%c",&ch);
 tmp = getchar(); //忽略斷行符號符
 if(ch == '&')    //輸入&符號表示此節點為空白
 {
  printf("Null BiTreeNode Created!/n");
  T = NULL;
  return NULL;
 }
 
 T = (struct BiTNode *)malloc(sizeof(BiTNode)); //為當前節點分配記憶體
 if(!T)
 {
  printf("Allocate memory failed!/n");
  return NULL;
 }

 T->data = ch;  //為當前節點賦值

 T->lchild = CreateBiTree();  //遞迴建立左子樹
 T->rchild = CreateBiTree(); //遞迴建立右子樹

 return T; 
}

//銷毀二叉樹,銷毀成功返回0,錯誤返回1
int DestroyBiTree(struct BiTNode* T)
{
 if(T)
 {
  struct BiTNode* lchild = T->lchild;
  struct BiTNode* rchild = T->rchild;
  free(T);
  if(0 == DestroyBiTree(lchild))
  {
   if(0 == DestroyBiTree(rchild))
    return 0;
   else
    return 1;
  }
 } 
 return 0;
}
//訪問節點元素
int visit(char elem)
{
 if(elem == '&')
  return 1;
 printf("%c ",elem);
 return 0;
}

//先序遍曆遞迴演算法,傳回值為0表示遍曆成功,1為失敗
int PreOrderTraverse_R(struct BiTNode* T, int (*visit)(char elem))
{
 if(T)
 {
  if(0 != visit(T->data))  //訪問根節點
   return 1;

  if(T->lchild)
  {
   if(0 != InOrderTraverse_R(T->lchild,visit)) //遞迴遍曆左子樹
    return 1;
  }
  
  if(T->rchild)
  {
   if(0 != InOrderTraverse_R(T->rchild,visit)) //遞迴遍曆右子樹
    return 1;
  }  
 } 
 return 0;   
}

//中序遍曆遞迴演算法,傳回值為0表示遍曆成功,1為失敗
int InOrderTraverse_R(struct BiTNode* T, int (*visit)(char elem))
{
 if(T)
 {
  if(T->lchild)
  {
   if(0 != InOrderTraverse_R(T->lchild,visit)) //遞迴遍曆左子樹
    return 1;
  }
  
  if(0 != visit(T->data))  //訪問根節點
   return 1;
  
  if(T->rchild)
  {
   if(0 != InOrderTraverse_R(T->rchild,visit)) //遞迴遍曆右子樹
    return 1;
  }  
 } 
 return 0;  
}

//後序遍曆遞迴演算法,返回0表示遍曆成功,1為失敗
int PostOrderTraverse_R(struct BiTNode* T, int (*visit)(char elem))
{
 if(T)
 {
  if(T->lchild)
  {
   if(0 != PostOrderTraverse_R(T->lchild,visit)) //遞迴遍曆左子樹
    return 1;
  }
  
  if(T->rchild)
  {
   if(0 != PostOrderTraverse_R(T->rchild,visit)) //遞迴遍曆右子樹
    return 1;
  }
  
  if(0 != visit(T->data))  //訪問根節點
   return 1;
 } 
 return 0;     
}

//先序遍曆非遞迴演算法
void PreOrderTraverse(struct BiTNode* T, int (*visit)(char elem))
{
 struct stack ss;
 struct BiTNode* p = T;
 initStack(&ss); 
 while(p||!isEmpty(&ss))
 {
  if(p)
  {
   visit(p->data);
   push(&ss,p);
   p=p->lchild;
  }
  else
  {
   p = getTop(&ss);
   pop(&ss);
   p = p->rchild;
  }
 }
}

//中序遍曆非遞迴演算法
void InOrderTraverse(struct BiTNode* T, int (*visit)(char elem))
{
 struct stack ss;
 struct BiTNode* p;
 initStack(&ss);

 push(&ss,T);
 while(!isEmpty(&ss))
 {
  while(p = getTop(&ss))
   push(&ss,p->lchild); //向左走到盡頭
  p = pop(&ss);  //null 指標退棧

  if(!isEmpty(&ss))
  {
   p = pop(&ss);
   visit(p->data);  //訪問節點
   push(&ss,p->rchild); //向右一步
  }
 }
}

//後序遍曆非遞迴演算法
void PostOrderTraverse(struct BiTNode* T, int (*visit)(char elem))
{
 struct stack ss;
 struct BiTNode* p = T;
 struct BiTNode* q;
 initStack(&ss); //初始化空棧

 while(p || !isEmpty(&ss))
 {
  if(p)
  {
   push(&ss,p);
   p = p->lchild;
  }
  else
  {
   p =getTop(&ss);
   if(p)
   {
    push(&ss,NULL);
    p = p->rchild;
   }
   else
   {
    pop(&ss);
    q = pop(&ss);
    visit(q->data);
   }
  }
 }
}

 

//main.c 測試主程式

#include<stdio.h>
#include "BiTree.h"

int main()
{
 struct BiTNode* bt = 0;
 bt = CreateBiTree(bt);
 printf("先序遍曆序列:/n");
 PreOrderTraverse_R(bt,visit);
 printf("/n中序遍曆序列:/n");
 InOrderTraverse_R(bt,visit);
 printf("/n後序遍曆序列:/n");
 PostOrderTraverse_R(bt,visit);

 printf("/n非遞迴先序遍曆序列:/n");
 PreOrderTraverse(bt,visit);

 printf("/n非遞迴中序遍曆序列:/n");
 InOrderTraverse(bt,visit);

 printf("/n非遞迴後序遍曆序列:/n");
 PostOrderTraverse(bt,visit);
 DestroyBiTree(bt);
 return 0;
}

 

 

 

 

    根據書上的演算法寫的,書上演算法以數組0下標元素做哨兵,考慮到輸入數組的時候不可能留個哨兵位置,就改寫了一點,可以從0下標開始進行插入排序。

/*================================================================================

功能:對可以使用<進行比較的元素數組進行直接插入排序

作者:sunnyrain

日期:2008-09-10

編譯環境:VC++6.0

=================================================================================*/

#include<iostream>
using namespace std;

template<class T>
void InsertSort(T* p,size_t length)
{
 T senti; //替代哨兵p[0]
 int i,j;
 for(i=1;i<length;++i)
 {
  if(p[i]<p[i-1])
  {
   senti = p[i];
   for(j=i-1;senti<p[j] && j>=0;--j)  //與有哨兵的相比這裡多了j>=0,否則會越界錯誤
   {
    p[j+1] = p[j];
   }
   p[j+1] = senti;
  }  
 } 
}

int main()
{
 int a[10] ; //= {4,12,35,62,11,2,4,99,65,1};
 cout<<"Input ten integers :"<<endl;
 for(int i=0;i<10;i++)
 {
  cin>>a[i];
 }
 cout<<endl;
 InsertSort(a,10);
 cout<<"After sort:"<<endl;
 for(int j=0;j<10;j++)
 {
  cout<<a[j]<<" ";
 }
 return 0;
}

 

 

  其實和直接插入排序沒有太大區別,只是尋找過程使用了折半尋找,總時間複雜度還是O(n^2),藉此複習一下折半尋找而已。

/*================================================================================

功能:對可以使用<進行比較的元素數組進行折半插入排序

作者:sunnyrain

日期:2008-09-10

編譯環境:VC++6.0

=================================================================================*/

#include<iostream>
using namespace std;

template<class T>
void BInsertSort(T* p,size_t length)
{
 T senti; //替代哨兵p[0]
 int i,j,low,high,mid;
 for(i=1;i<length;++i)
 {
  low = 0;
  high = i-1;
  mid = (low + high)/2;
  while(low <= high)  //折半尋找過程
  {
   if(p[i] > p[mid])
   {
    low =  mid + 1;
    mid = (low + high)/2;
   }
   else
   {
    high = mid - 1;
    mid = (low + high)/2;
   }
  }
  
  senti = p[i];  
  for(j=i-1; j>=mid;--j)  //移動元素&插入
  {
   p[j+1] = p[j];
  }
  p[high+1] = senti;  //這裡要用high代替j,否則當插入元素比前面所有元素都大時會出錯
  
 } 
}

int main()
{
 int a[10] = {4,12,35,62,11,2,4,99,65,1};
/* cout<<"Input ten integers :"<<endl;
 for(int i=0;i<10;i++)
 {
  cin>>a[i];
 }*/
 cout<<endl;
 BInsertSort(a,10);
 cout<<"After sort:"<<endl;
 for(int j=0;j<10;j++)
 {
  cout<<a[j]<<" ";
 }
 return 0;
}

 

 

 

    書上的表插入排序沒有給演算法,雖然看起來很簡單,由於是個環形鏈表,還是折騰了半天才找到正確插入位置。後面的重排是書上演算法,抄過來還是很容易的

/*================================================================================

功能:表插入排序c++實現

作者:sunnyrain

日期:2008-09-11

編譯環境:VC++6.0

=================================================================================*/

#include<iostream>
using namespace std;
const int SIZE = 100;

template<class T>
struct SLNode{
 T elem;
 int next;
};

template<class T>
struct List{
 SLNode<T> r[SIZE];
 int length;
};

template<class T>
void tableSort(List<T>& list)  //表插入排序
{
 list.r[0].next = 1;
 list.r[1].next = 0;
 for(int i=2;i<list.length;i++)
 {
  int j = list.r[0].next;
  int pre = 0; //記錄當前結點的前一位置
  while(list.r[i].elem >= list.r[j].elem && j>0) //找插入位置
  {
   pre = j;
   j = list.r[j].next; //鏈表向前走一步
  }
  list.r[i].next = j;  //插入的結點next域指向j結點
  list.r[pre].next = i; //插入結點的前一個結點的next域指向插入結點
 } 
}

template<class T>
void Arrange(List<T>& list)   //重排
{
 int pre = list.r[0].next;
 for(int i=1;i<list.length;i++)
 {
  while(pre<i)
   pre = list.r[pre].next;
  int q = list.r[pre].next;
  if(pre != i)
  {
   SLNode<T> temp = list.r[pre];
   list.r[pre] = list.r[i];
   list.r[i] = temp;
   list.r[i].next = pre;
  }
  pre = q;
 }
}

int main()
{
 List<int> list;
 int length = 8;
 
// cout<<"請輸入表長度:"<<endl;
// cin>>length;
 
 list.length = length + 1;
// cout<<"請輸入 "<<length<<" 個數字:"<<endl;
 
/* for(int i=1;i<list.length;i++)
 {
  cin>>list.r[i].elem;
 }*/
 list.r[1].elem = 49;
 list.r[2].elem = 38;
 list.r[3].elem = 65;
 list.r[4].elem = 97;
 list.r[5].elem = 76;
 list.r[6].elem = 13;
 list.r[7].elem = 27;
 list.r[8].elem = 49;
 
 for(int i=1;i<list.length;i++)
 {
  list.r[i].next = -1;
 }
 
 tableSort(list);  //進行表插入排序

 cout<<"排序結果(指標域順序):"<<endl;
 for(i=0;i<length+1;i++)
  cout<<list.r[i].next<<"/t";
 cout<<endl;

 cout<<"重排結果:"<<endl;
 Arrange(list);    //重排靜態鏈表
 for(i=1;i<list.length;i++)
 {
  cout<<list.r[i].elem<<"/t";
 }
 cout<<endl;
 
 for(i=1;i<list.length;i++)
 {
  cout<<list.r[i].next<<"/t";
 }
 cout<<endl;

 return 0;
}

 

 

 

/*================================================================================

功能:shell排序c++實現

作者:演算法都抄書上的,我就不算作者啦,作者嚴蔚敏吧,嘿嘿

日期:2008-09-11

編譯環境:VC++6.0

=================================================================================*/

#include<iostream>
using namespace std;

template<class T>
void ShellInsert(T* p,size_t length,int dk)  //一趟shell排序
{
 T temp;
 for(int i=dk;i<length;++i)
 {
  if(p[i]<p[i-dk])
  {
   temp = p[i];
   for(int j=i-dk;j>=0 && temp<p[j];j-=dk) //一趟插入過程
    p[j+dk] = p[j];
   p[j+dk] = temp;
  }
 }
}

template<class T>
void ShellSort(T* p,size_t length, int dlta[],int t)
{
 for(int k=0;k<t;++k)
 {
  ShellInsert(p,length,dlta[k]);
  for(int j=0;j<length;j++) //列印每一趟排序後的結果
  {
   cout<<p[j]<<"/t";
  }
  cout<<endl;
 }
}

int main()
{
 int a[10] = {49,38,65,97,76,13,27,49,55,4};
 int dlta[] = {9,5,3,1};  // dlta[k] = 2^(t-k)+1,t=3
/* cout<<"Input ten integers :"<<endl;
 for(int i=0;i<10;i++)
 {
  cin>>a[i];
 }
 cout<<endl;*/
 ShellSort(a,10,dlta,4);
 cout<<"After sort:"<<endl;
 for(int j=0;j<10;j++)
 {
  cout<<a[j]<<" ";
 }
 return 0;
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.